opensourceprojects.dev

A broadsheet for software that doesn't ask for your email

Axum: HTTP routing that gets tracing, compression, and timeouts for free via tow...
GitHub RepoImpressions3

Project Description

View on GitHub

Axum: Get Tracing, Compression, and Timeouts Without Building a Middleware System

You've probably written the same middleware plumbing more than once—logging here, a timeout layer there, compression bolted on somewhere else. What if your HTTP framework just handed you all of that because it borrowed an existing ecosystem instead of reinventing one? That's the pitch behind axum, an HTTP routing and request-handling library from the tokio-rs team that focuses on ergonomics and modularity.

What It Does

At its core, axum routes requests to handlers and lets you parse incoming requests declaratively using extractors. It's built on top of hyper and integrates directly with the tower and tower-http ecosystems. Rather than shipping its own middleware system, axum uses tower::Service as its abstraction layer.

The high-level feature list is short and to the point: route requests to handlers with a macro-free API, parse requests with extractors, handle errors in a simple and predictable way, and generate responses with minimal boilerplate. The last feature is the one that shapes everything else—taking full advantage of tower and tower-http for middleware, services, and utilities.

It's written in Rust, uses #![forbid(unsafe_code)] to guarantee everything is implemented in 100 percent safe Rust, and has a minimum supported Rust version of 1.80. Performance-wise, it's a thin layer over hyper, so it adds very little overhead.

Why It's Cool

It doesn't have a middleware system, and that's the point. Most frameworks build their own middleware abstractions, which means the middleware you write only works inside that framework. axum skips this entirely by leaning on tower::Service. The result is that you get timeouts, tracing, compression, authorization, and more for free—not because axum implemented them, but because tower already did.

Your middleware isn't trapped. Because axum uses the same Service trait that tower defines, you can share middleware with applications written using hyper or tonic. If you've got a gRPC service and an HTTP service in the same codebase, they can reuse the same layers. That's a real practical win, not a theoretical one.

The API stays out of your way. The routing API is macro-free, which means no proc-macro magic obscuring what's happening. You write Router::new().route("/", get(root)) and that's it. Handlers are just async functions, and extractors like Json(payload) tell axum how to parse the request body—the function signature does the work.

Extractors make request parsing declarative. Instead of manually pulling apart a request, you describe what you want in the handler's arguments. In the README example, Json(payload): Json<CreateUser> parses the body into a typed struct. The handler returns (StatusCode, Json<User>), which becomes a JSON response with a status code. Minimal boilerplate, clear intent.

Error handling is predictable. The README calls out a "simple and predictable error handling model" as a core feature. That matters—error handling is usually where frameworks get messy, and having it be a first-class design concern is worth noting.

It's honest about performance. Rather than claiming to be the fastest thing ever, the README says performance is "comparable to hyper" and links to third-party benchmarks. That kind of restraint is refreshing.

How to Try It

Getting started is straightforward if you're already in the Rust ecosystem.

  1. Add axum to your Cargo.toml (check crates.io for the current version—the README notes that main currently contains breaking changes toward 0.9, so use the 0.8.x branch for what's released).

  2. Build a router and serve it. The README example is a complete, runnable app:

use axum::{
    routing::{get, post},
    http::StatusCode,
    Json, Router,
};
use serde::{Deserialize, Serialize};

#[tokio::main]
async fn main() {
    tracing_subscriber::fmt::init();

    let app = Router::new()
        .route("/", get(root))
        .route("/users", post(create_user));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await;
}
  1. Check the examples directory in the repo for more complete projects, and the crate documentation for additional snippets.

The repository is at github.com/tokio-rs/axum. If you get stuck, there's a Discord channel and a discussions forum linked from the README.

Final Thoughts

axum is best suited for developers who are already comfortable with tower and hyper, or who are willing to learn them—because that's where a lot of its power lives. If you want a framework that hides all the plumbing, this might not be the one. But if you want routing that composes cleanly with middleware you can reuse elsewhere, the design is hard to argue with. The fact that it's from the tokio-rs team and uses 100 percent safe Rust doesn't hurt either. Worth a look if you're building HTTP services in Rust.


Follow @githubprojects for more developer tools and open source projects.

Back to Projects
Project ID: eb6fcfa2-8227-4cf6-aacf-d945c424b174Last updated: September 10, 2026 at 05:44 AM