serve
serve(port: u16) -> std::io::Result<()> is the one-call entry point: load config, build the DI
container, wire up every auto-registered route, and run the server.
use axumstart::router::get;
#[get("/health")]
async fn health() -> &'static str {
"ok"
}
#[tokio::main]
async fn main() -> std::io::Result<()> {
axumstart::serve(3000).await
}
What it does, in order
- Loads
.envfrom the current working directory (dotenvy::dotenv().ok()— silently does nothing if there isn't one). This runs before components are built, so#[derive(ComponentConfig)]'s#[env_var(...)]fields see values from it, not just pre-existing process environment variables. - Registers components via
ComponentProvider::register_all()(every#[component]/#[derive(Component)]/#[derive(ComponentConfig)]type). - Builds the registered blueprints into a
Componentssnapshot. - Folds every auto-registered route (every
#[get]/#[post]/etc. handler — see HTTP methods) onto a freshaxum::Router, with thatComponentsvalue available to any#[layer(...)]factory that wants it. - Attaches
Componentsas the router's state and binds aTcpListeneron0.0.0.0:{port}, then runsaxum::serve.
Feature gating
serve requires the router feature (which implies components) — both are default
features, so most consumers get it for free:
axumstart = { version = "..." }
If you've opted out with default-features = false, add it back explicitly:
axumstart = { version = "...", default-features = false, features = ["router"] }
When you need more than serve gives you
serve only serves auto-registered routes, with no hook for a manually-built Router, global
middleware, .merge()-ing in another router, or custom listener configuration. If you need any
of that, skip serve and call the pieces it wraps yourself:
use axumstart::components::ComponentProvider;
use axumstart::router::register_routes;
#[tokio::main]
async fn main() -> std::io::Result<()> {
dotenvy::dotenv().ok();
let provider = ComponentProvider::default();
provider.register_all();
let state = provider.build().await;
let app = register_routes(axum::Router::new(), &state)
.merge(my_manual_router())
.layer(tower_http::trace::TraceLayer::new_for_http()) // global middleware
.with_state(state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
axum::serve(listener, app).await
}
# fn my_manual_router() -> axum::Router<axumstart::router::Components> { axum::Router::new() }