Why "batteries included"?
Loco’s tagline is “Axum with batteries included,” and it is meant literally: everything under the hood is standard Axum 0.8 and Tower, but almost none of the code you’d normally write to assemble a production web service in Rust — wiring a DB pool into state, picking a logging stack, hand-rolling a queue, choosing a config format — is code you have to write yourself. This page explains the design principle behind that choice, not the mechanics (those live in Architecture and the reference pages).
The prime directive
When a Loco app needs a capability, the framework’s bias is:
- Reach for a built-in first. Database access, caching, background jobs, mailing, file storage, view rendering, JWT auth, health checks, a CLI — these already exist, wired into
AppContextand toggled from YAML. - Reach for a generator second.
cargo loco generatescaffolds the idiomatic shape of a model, controller, worker, mailer, task, or full CRUD scaffold. The generated code is not a black box — it’s a starting point you own and edit. - Hand-wire only as a last resort, and when you do, Loco gives you a small number of well-defined seams to do it safely —
Hooks,Initializer,SharedStore,before_routes/after_routes— rather than forcing you to fork the framework or reassemblemain()from scratch.
This ordering is the single idea that explains most of what looks, from a plain-Axum perspective, like “magic”: it isn’t magic, it’s a library of pre-wired decisions with an escape hatch at every layer.
What “hand-wiring” looks like without it
A typical Axum service starts every project by re-deciding things that have already been decided a thousand times: which connection-pool settings, which logging crate, how to get the DB handle into every handler, how config and secrets flow in, how a background job survives a restart. None of these decisions are hard, but making them again, per project, is where hours disappear and where inconsistency creeps in between a team’s services.
Loco’s coming-from-axum page walks through this delta concretely (pool setup, AddExtensionLayer state wiring, env_logger vs tracing, main.rs assembly) for a real reference app. The short version: every one of those steps becomes either a YAML key or a generator invocation in Loco, and the underlying Axum Router/State/extractor model is unchanged — so nothing about Axum’s own learning curve is hidden from you.
What Loco integrates
Batteries, concretely, means the following are already implemented, tested, and reachable from AppContext or a Hooks default, rather than left as an exercise:
- Routing & the request pipeline —
AppRoutes/Routescompile down to a realaxum::Router<AppContext>; a documented, ordered stack of middleware (payload limits, CORS, compression, timeouts, security headers, request IDs, a static file server, a dev-mode fallback page, and more) is available with a config flip rather than atower::Layeryou write by hand. See Architecture and the middleware catalog. - Data & persistence — Sea-ORM 2.0 entities, migrations, and a query/pagination layer are generated from a compact field-type DSL (
cargo loco generate model ...), not written by hand column-by-column. - Background processing — one
BackgroundWorkertrait and oneperform_latercall site work unmodified against three interchangeable queue backends (Redis, Postgres, SQLite); see The background-processing model. - Scheduling & tasks — a cron-like scheduler (English or cron syntax) and ad-hoc CLI-invokable tasks, both driven from the same
Tasks/Hooksregistration points, no separate process supervisor to build. - Caching, storage, mail — a
Cachewith in-memory/Redis/null backends, a multi-driverStorageabstraction (local/memory/S3/Azure/GCS) with single and replicated (mirror/backup) strategies, and aMailerwith SMTP/STARTTLS/implicit-TLS and a stub-for-tests mode — each a field onAppContext, each swappable by config or feature flag rather than by rewriting call sites. - Views — server-rendered Tera templates, JSON views, or a single-binary
embedded_assetsbuild, chosen without touching controller code. See Views and assets. - Auth & security — JWT (HS512 by default, multi-location token extraction) and API-key extractors implementing the same
FromRequestPartspattern as everything else in Axum. - Operability — structured
tracinglogging with sane third-party filtering out of the box,/_ping//_health//_readinessendpoints, acargo loco doctordiagnostic command, and acargo loco routes/middlewareintrospection CLI. - Configuration — one typed
Configstruct, one environment-resolution rule, one file-precedence rule, and Tera’s ownget_envfor secrets — see The configuration model.
None of this requires a plugin marketplace or a runtime registry: it’s all compiled into loco-rs behind Cargo feature flags (see the feature-flags reference), so an app only pays for what it turns on.
The corollary: escape hatches, not walls
“Batteries included” only works as a philosophy if it doesn’t become “batteries mandatory.” Every built-in in Loco has a documented seam for replacing or bypassing it:
- Don’t like the default middleware stack? Override
Hooks::middlewaresand return your ownVec<Box<dyn MiddlewareLayer>>. - Want a raw Axum router mounted verbatim?
Hooks::before_routes/after_routeshand you a realaxum::Routerto mutate directly — the Coming from Axum page shows this as the literal drop-in path for existing Axum code. - Need a service that isn’t a first-class
AppContextfield (a third-party API client, a feature-flag SDK)?AppContext.shared_storeis a type-keyed DI container built for exactly that — see AppContext and dependency injection. - Want to own the tracing/logging stack yourself? Return
Ok(true)fromHooks::init_loggerand Loco steps aside. - Want a different view engine than Tera? Implement
ViewRendererand swap it in via anInitializer.
This is the same shape as Rails’ “convention over configuration,” reframed for a language where a global mutable app instance isn’t an option: Loco supplies the convention as a compiled-in default, and the configuration/override points are explicit, typed, and ordered — not implicit and discoverable only by reading source. The rest of this Explanation cluster works through each of those seams — boot lifecycle, DI, config loading, background jobs, views, and the Axum relationship — in more depth.