> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/tokio-rs/axum/llms.txt
> Use this file to discover all available pages before exploring further.

# Tower integration

> Leverage the Tower middleware ecosystem with Axum

Axum is built on top of [Tower](https://github.com/tower-rs/tower), a library of modular and reusable components for building robust networking clients and servers. This deep integration gives you access to a rich ecosystem of middleware.

## Understanding Tower

Tower provides three core abstractions:

* **Service**: An asynchronous function from a request to a response
* **Layer**: Middleware that wraps a service to modify its behavior
* **ServiceBuilder**: A utility for composing layers

<Info>
  Axum's `Router` implements `tower::Service`, so it works seamlessly with all Tower middleware.
</Info>

## Adding middleware with layers

Use the `.layer()` method to add Tower middleware:

```rust theme={null}
use axum::Router;
use tower_http::trace::TraceLayer;

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

### Middleware execution order

Middleware executes in reverse order of how it's added:

```rust theme={null}
use tower_http::{
    compression::CompressionLayer,
    cors::CorsLayer,
    trace::TraceLayer,
};

let app = Router::new()
    .route("/api/data", get(get_data))
    .layer(CompressionLayer::new())  // Runs third (closest to handler)
    .layer(CorsLayer::permissive())  // Runs second
    .layer(TraceLayer::new_for_http()); // Runs first (outermost)
```

Execution flow:

1. Request → TraceLayer → CorsLayer → CompressionLayer → Handler
2. Handler → CompressionLayer → CorsLayer → TraceLayer → Response

## tower-http middleware

The [`tower-http`](https://docs.rs/tower-http) crate provides HTTP-specific middleware:

### CORS

Handle Cross-Origin Resource Sharing:

```rust theme={null}
use axum::{routing::get, Router, Json};
use tower_http::cors::{CorsLayer, Any};
use http::Method;

let cors = CorsLayer::new()
    .allow_origin("http://localhost:3000".parse::<HeaderValue>().unwrap())
    .allow_methods([Method::GET, Method::POST])
    .allow_headers(Any);

let app = Router::new()
    .route("/api/data", get(get_data))
    .layer(cors);
```

<Accordion title="Advanced CORS configuration">
  ```rust theme={null}
  use tower_http::cors::{CorsLayer, AllowOrigin};
  use http::{header, Method};

  let cors = CorsLayer::new()
      .allow_origin(AllowOrigin::predicate(|origin, _| {
          // Custom origin validation logic
          origin.as_bytes().ends_with(b".example.com")
      }))
      .allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE])
      .allow_headers([header::CONTENT_TYPE, header::AUTHORIZATION])
      .allow_credentials(true)
      .max_age(Duration::from_secs(3600));
  ```
</Accordion>

### Compression

Compress response bodies:

```rust theme={null}
use tower_http::compression::CompressionLayer;
use tower_http::decompression::RequestDecompressionLayer;

let app = Router::new()
    .route("/api/data", get(large_data).post(receive_data))
    .layer(RequestDecompressionLayer::new())  // Decompress requests
    .layer(CompressionLayer::new());          // Compress responses
```

Supported algorithms: gzip, deflate, br (brotli), zstd

### Tracing and logging

Log requests and responses:

<CodeGroup>
  ```rust Basic tracing theme={null}
  use tower_http::trace::TraceLayer;

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

  ```rust Custom tracing theme={null}
  use tower_http::trace::{TraceLayer, DefaultMakeSpan, DefaultOnResponse};
  use tower_http::LatencyUnit;
  use tracing::Level;

  let app = Router::new()
      .route("/", get(handler))
      .layer(
          TraceLayer::new_for_http()
              .make_span_with(
                  DefaultMakeSpan::new()
                      .include_headers(true)
                      .level(Level::INFO)
              )
              .on_response(
                  DefaultOnResponse::new()
                      .include_headers(true)
                      .latency_unit(LatencyUnit::Micros)
              )
      );
  ```

  ```rust Fully custom tracing theme={null}
  use tower_http::trace::TraceLayer;
  use axum::{
      body::Bytes,
      extract::{Request, MatchedPath},
      response::Response,
  };
  use tracing::{info_span, Span};
  use std::time::Duration;

  let app = Router::new()
      .route("/api/:id", get(handler))
      .layer(
          TraceLayer::new_for_http()
              .make_span_with(|request: &Request<_>| {
                  let matched_path = request
                      .extensions()
                      .get::<MatchedPath>()
                      .map(MatchedPath::as_str);

                  info_span!(
                      "http_request",
                      method = ?request.method(),
                      matched_path,
                  )
              })
              .on_request(|_request: &Request<_>, _span: &Span| {
                  tracing::info!("started processing request");
              })
              .on_response(|_response: &Response, latency: Duration, _span: &Span| {
                  tracing::info!("response generated in {:?}", latency);
              })
      );
  ```
</CodeGroup>

### Request timeouts

Set timeouts for requests:

```rust theme={null}
use tower_http::timeout::TimeoutLayer;
use std::time::Duration;

let app = Router::new()
    .route("/slow", get(slow_handler))
    .layer(TimeoutLayer::new(Duration::from_secs(10)));
```

With custom error status:

```rust theme={null}
use tower_http::timeout::TimeoutLayer;
use axum::http::StatusCode;

let app = Router::new()
    .route("/api/data", get(handler))
    .layer(
        TimeoutLayer::with_status_code(
            StatusCode::REQUEST_TIMEOUT,
            Duration::from_secs(30),
        )
    );
```

### Request/response size limits

```rust theme={null}
use tower_http::limit::RequestBodyLimitLayer;
use axum::extract::DefaultBodyLimit;

let app = Router::new()
    .route("/upload", post(upload_handler))
    // Disable default 2MB limit
    .layer(DefaultBodyLimit::disable())
    // Set custom limit (100MB)
    .layer(RequestBodyLimitLayer::new(100 * 1024 * 1024));
```

### Static file serving

Serve static files:

```rust theme={null}
use tower_http::services::{ServeDir, ServeFile};

let app = Router::new()
    .route("/api/hello", get(api_handler))
    // Serve files from ./assets directory
    .nest_service("/assets", ServeDir::new("assets"))
    // Serve a single file
    .route_service("/favicon.ico", ServeFile::new("assets/favicon.ico"));
```

With directory listings and index files:

```rust theme={null}
use tower_http::services::ServeDir;

let serve_dir = ServeDir::new("assets")
    .append_index_html_on_directories(true)
    .precompressed_gzip()
    .precompressed_br();

let app = Router::new()
    .nest_service("/static", serve_dir);
```

## ServiceBuilder for composing middleware

Use `ServiceBuilder` to organize multiple layers:

```rust theme={null}
use tower::ServiceBuilder;
use tower_http::{
    compression::CompressionLayer,
    cors::CorsLayer,
    trace::TraceLayer,
    timeout::TimeoutLayer,
};
use std::time::Duration;

let middleware = ServiceBuilder::new()
    .layer(TraceLayer::new_for_http())
    .layer(TimeoutLayer::new(Duration::from_secs(10)))
    .layer(CompressionLayer::new())
    .layer(CorsLayer::permissive());

let app = Router::new()
    .route("/api/data", get(handler))
    .layer(middleware);
```

<Info>
  `ServiceBuilder` applies layers in the order they appear (unlike `.layer()` which applies them in reverse).
</Info>

## Per-route middleware

Apply middleware to specific routes:

```rust theme={null}
use axum::{
    middleware::{self, Next},
    response::Response,
    extract::Request,
};

async fn auth_middleware(request: Request, next: Next) -> Response {
    // Check authentication
    let auth_header = request.headers()
        .get("Authorization")
        .and_then(|h| h.to_str().ok());
    
    if auth_header != Some("Bearer secret") {
        return (StatusCode::UNAUTHORIZED, "Unauthorized").into_response();
    }
    
    next.run(request).await
}

let app = Router::new()
    .route("/public", get(public_handler))
    .route("/protected", get(protected_handler)
        .layer(middleware::from_fn(auth_middleware)));
```

## Sharing state with middleware

Use extensions to share data:

```rust theme={null}
use axum::{
    extract::{Extension, Request},
    middleware::Next,
    response::Response,
};
use uuid::Uuid;

#[derive(Clone)]
struct RequestId(String);

async fn set_request_id(mut request: Request, next: Next) -> Response {
    let request_id = RequestId(Uuid::new_v4().to_string());
    request.extensions_mut().insert(request_id.clone());
    
    let mut response = next.run(request).await;
    response.headers_mut().insert(
        "x-request-id",
        request_id.0.parse().unwrap(),
    );
    response
}

async fn handler(Extension(request_id): Extension<RequestId>) -> String {
    format!("Request ID: {}", request_id.0)
}

let app = Router::new()
    .route("/", get(handler))
    .layer(middleware::from_fn(set_request_id));
```

## Custom Tower middleware

Create your own middleware:

```rust theme={null}
use tower::{Layer, Service};
use std::task::{Context, Poll};
use std::future::Future;
use std::pin::Pin;

#[derive(Clone)]
struct MyMiddleware<S> {
    inner: S,
}

impl<S, B> Service<Request<B>> for MyMiddleware<S>
where
    S: Service<Request<B>>,
{
    type Response = S::Response;
    type Error = S::Error;
    type Future = S::Future;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.inner.poll_ready(cx)
    }

    fn call(&mut self, request: Request<B>) -> Self::Future {
        // Modify request here
        println!("Request: {} {}", request.method(), request.uri());
        self.inner.call(request)
    }
}

#[derive(Clone)]
struct MyLayer;

impl<S> Layer<S> for MyLayer {
    type Service = MyMiddleware<S>;

    fn layer(&self, inner: S) -> Self::Service {
        MyMiddleware { inner }
    }
}

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

## Common middleware patterns

<CodeGroup>
  ```rust Request ID tracking theme={null}
  use tower_http::request_id::{
      MakeRequestId, RequestId, PropagateRequestIdLayer, SetRequestIdLayer,
  };
  use uuid::Uuid;

  #[derive(Clone)]
  struct MakeRequestUuid;

  impl MakeRequestId for MakeRequestUuid {
      fn make_request_id<B>(&mut self, _request: &Request<B>) -> Option<RequestId> {
          let id = Uuid::new_v4().to_string().parse().unwrap();
          Some(RequestId::new(id))
      }
  }

  let app = Router::new()
      .layer(SetRequestIdLayer::x_request_id(MakeRequestUuid))
      .layer(PropagateRequestIdLayer::x_request_id());
  ```

  ```rust Rate limiting (with tower-governor) theme={null}
  use tower_governor::{
      governor::GovernorConfigBuilder,
      GovernorLayer,
  };

  let governor_conf = Box::new(
      GovernorConfigBuilder::default()
          .per_second(10)
          .burst_size(20)
          .finish()
          .unwrap(),
  );

  let app = Router::new()
      .route("/api", get(handler))
      .layer(GovernorLayer { config: governor_conf });
  ```
</CodeGroup>

## Testing with Tower

```rust theme={null}
#[cfg(test)]
mod tests {
    use tower::ServiceExt; // for `oneshot`
    use axum::{
        body::Body,
        http::{Request, StatusCode},
    };

    #[tokio::test]
    async fn test_with_middleware() {
        let app = Router::new()
            .route("/", get(|| async { "Hello" }))
            .layer(TraceLayer::new_for_http());

        let response = app
            .oneshot(Request::get("/").body(Body::empty()).unwrap())
            .await
            .unwrap();

        assert_eq!(response.status(), StatusCode::OK);
    }
}
```

<Warning>
  Be careful with middleware ordering. Request processing flows from outer to inner layers, while response processing flows from inner to outer layers.
</Warning>

<Tip>
  Use `ServiceBuilder` when composing many middleware layers - it's more ergonomic and the layer order matches the execution order.
</Tip>
