Skip to main content
The router type for composing handlers and services. Router<S> means a router that is missing a state of type S to be able to handle requests. Thus, only Router<()> (i.e. without missing state) can be passed to serve. See Router::with_state for more details.

Constructor

Router::new()
fn() -> Router<S>
Create a new Router.Unless you add additional routes this will respond with 404 Not Found to all requests.
use axum::Router;

let app = Router::new();

Routing methods

route
fn(self, path: &str, method_router: MethodRouter<S>) -> Self
Add a route to the router.The path can contain dynamic segments starting with : or catch-all segments starting with *.
use axum::{Router, routing::get};

let app = Router::new()
    .route("/", get(|| async { "Hello, World!" }))
    .route("/users/:id", get(|| async { "User profile" }));
route_service
fn<T>(self, path: &str, service: T) -> Self
Add a service as a route.Similar to route but accepts any Service instead of a MethodRouter.Note: Cannot be used with Routers - use nest instead.
use axum::{Router, extract::Request};
use tower::service_fn;
use std::convert::Infallible;

let service = tower::service_fn(|request: Request| async {
    Ok::<_, Infallible>("Hello from service")
});

let app = Router::new()
    .route_service("/service", service);
nest
fn(self, path: &str, router: Self) -> Self
Nest another router at a given path.All routes in the nested router will be prefixed with the given path. The path cannot be empty or / - use merge instead.
use axum::{Router, routing::get};

let api_routes = Router::new()
    .route("/users", get(|| async { "List users" }))
    .route("/posts", get(|| async { "List posts" }));

let app = Router::new()
    .nest("/api", api_routes);
// Routes: /api/users, /api/posts
nest_service
fn<T>(self, path: &str, service: T) -> Self
Like nest, but accepts an arbitrary Service.The path cannot be empty or /.
use axum::{Router, extract::Request};
use tower::service_fn;
use std::convert::Infallible;

let service = tower::service_fn(|request: Request| async {
    Ok::<_, Infallible>("Nested service")
});

let app = Router::new()
    .nest_service("/service", service);
merge
fn<R>(self, other: R) -> Self where R: Into<Self>
Merge two routers into one.This is useful for combining multiple routers that have routes at the root level. Both routers cannot have a custom fallback.
use axum::{Router, routing::get};

let app = Router::new()
    .route("/foo", get(|| async { "foo" }));

let api = Router::new()
    .route("/bar", get(|| async { "bar" }));

let merged = app.merge(api);
// Routes: /foo, /bar

Middleware methods

layer
fn<L>(self, layer: L) -> Self
Apply a tower::Layer to the router.The layer will be applied to all routes and the fallback.
use axum::{Router, routing::get};
use tower_http::trace::TraceLayer;

let app = Router::new()
    .route("/", get(|| async { "Hello" }))
    .layer(TraceLayer::new_for_http());
route_layer
fn<L>(self, layer: L) -> Self
Apply a tower::Layer to the router’s routes, but not the fallback.This is useful when you want middleware to only apply to matched routes.
use axum::{Router, routing::get};
use tower_http::compression::CompressionLayer;

let app = Router::new()
    .route("/api/data", get(|| async { "data" }))
    .route_layer(CompressionLayer::new())
    .fallback(|| async { "Not found" });
// Compression applies to /api/data but not the fallback

Fallback methods

fallback
fn<H, T>(self, handler: H) -> Self
Add a fallback handler for requests that don’t match any routes.
use axum::{Router, routing::get, http::StatusCode};

let app = Router::new()
    .route("/", get(|| async { "Home" }))
    .fallback(|| async { (StatusCode::NOT_FOUND, "Page not found") });
fallback_service
fn<T>(self, service: T) -> Self
Add a fallback Service for requests that don’t match any routes.Like fallback but accepts a Service instead of a handler.
use axum::{Router, extract::Request};
use tower::service_fn;
use std::convert::Infallible;

let service = tower::service_fn(|_: Request| async {
    Ok::<_, Infallible>("Fallback service")
});

let app = Router::new()
    .fallback_service(service);
method_not_allowed_fallback
fn<H, T>(self, handler: H) -> Self
Set a custom handler for 405 Method Not Allowed responses.This handler is called when a route matches the path but not the HTTP method.
use axum::{Router, routing::get, http::StatusCode};

let app = Router::new()
    .route("/", get(|| async { "GET only" }))
    .method_not_allowed_fallback(|| async {
        (StatusCode::METHOD_NOT_ALLOWED, "Method not allowed")
    });
reset_fallback
fn(self) -> Self
Reset the fallback to its default.Useful to merge two routers with fallbacks, as merge doesn’t allow both routers to have an explicit fallback. Use this method to remove the one you want to discard before merging.
use axum::{Router, routing::get};

let app = Router::new()
    .route("/", get(|| async { "Home" }))
    .fallback(|| async { "Custom 404" })
    .reset_fallback();

State management

with_state
fn<S2>(self, state: S) -> Router<S2>
Provide the state for the router.This converts a Router<S> (missing state of type S) into a Router<()> that can be served.
use axum::{Router, routing::get, extract::State};

#[derive(Clone)]
struct AppState {
    db: String,
}

let app = Router::new()
    .route("/", get(|State(state): State<AppState>| async move {
        format!("Connected to: {}", state.db)
    }))
    .with_state(AppState { db: "postgres://...".to_string() });

Service conversion

into_make_service
fn(self) -> IntoMakeService<Self>
Convert this router into a MakeService.Only available for Router<()> (routers without missing state).
use axum::{Router, routing::get};

let app = Router::new()
    .route("/", get(|| async { "Hello, World!" }));

# async {
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await;
# };
into_make_service_with_connect_info
fn<C>(self) -> IntoMakeServiceWithConnectInfo<Self, C>
Convert the router into a MakeService which stores information about the incoming connection.Requires the tokio feature.
use axum::{Router, routing::get, extract::ConnectInfo};
use std::net::SocketAddr;

async fn handler(ConnectInfo(addr): ConnectInfo<SocketAddr>) -> String {
    format!("Hello {addr}")
}

let app = Router::new().route("/", get(handler));

# async {
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app.into_make_service_with_connect_info::<SocketAddr>()).await;
# };
as_service
fn<B>(&mut self) -> RouterAsService<'_, B, S>
Convert the router into a borrowed Service with a fixed request body type.This is mainly used when calling Router in tests to aid type inference.
use axum::{Router, routing::get, http::Request, body::Body};
use tower::{Service, ServiceExt};

# async fn example() -> Result<(), Box<dyn std::error::Error>> {
let mut router = Router::new().route("/", get(|| async {}));
let request = Request::new(Body::empty());
let response = router.as_service().ready().await?.call(request).await?;
# Ok(())
# }
into_service
fn<B>(self) -> RouterIntoService<B, S>
Convert the router into an owned Service with a fixed request body type.Similar to as_service but returns an owned Service.
use axum::{Router, routing::get};

let router = Router::new()
    .route("/", get(|| async { "Hello" }))
    .into_service();

Utility methods

has_routes
fn(&self) -> bool
Returns true if the router currently has at least one route added.
use axum::{Router, routing::get};

let router = Router::new();
assert!(!router.has_routes());

let router = router.route("/", get(|| async { "Hello" }));
assert!(router.has_routes());