Which Rust Web Framework Is Fastest? Benchmarking Actix, Axum, Rocket, and More

This article benchmarks several Rust web frameworks—including Actix, Axum, Rocket, Tide, Gotham, Nickel, Ntex, and Poem—using a simple "Hello World" test on a MacBook Pro, measuring request throughput, resource usage, and implementation difficulty across different concurrency levels.

21CTO
21CTO
21CTO
Which Rust Web Framework Is Fastest? Benchmarking Actix, Axum, Rocket, and More

Introduction

As Rust gains popularity, choosing the right web framework becomes crucial. This article compares the performance of eight Rust web frameworks—Actix, Axum, Rocket, Tide, Gotham, Nickel, Ntex, and Poem—using a basic "Hello World" benchmark.

Methodology

Each framework is tested with a minimal server that responds to Hello, World! requests. Benchmarks run on the same 2018 MacBook Pro (6‑core Intel i9, 32 GB RAM) using Apache Bench in release mode. Concurrency levels of 50, 100, and 150 connections are evaluated, each executing 1,000,000 requests.

Framework Implementations

Actix

[package]
name = "actix"
version = "0.1.0"
edition = "2021"

[dependencies]
actix-web = "4"
use actix_web::{get, App, HttpResponse, HttpServer, Responder};

#[get("/")]
async fn hello() -> impl Responder {
    HttpResponse::Ok().body("Hello world!")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new().service(hello)
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

Axum

[package]
name = "axum-hello"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.7.3"
tokio = { version = "1.0", features = ["full"] }
use axum::{response::Html, routing::get, Router};

#[tokio::main]
async fn main() {
    let app = Router::new().route("/", get(handler));
    let listener = tokio::net::TcpListener::bind("127.0.0.1:8080").await.unwrap();
    println!("listening on {}", listener.local_addr().unwrap());
    axum::serve(listener, app).await.unwrap();
}

async fn handler() -> Html<&'static str> {
    Html("Hello world!")
}

Rocket

[package]
name = "rocket-hello"
version = "0.1.0"
edition = "2021"

[dependencies]
rocket = "0.5.0"
#[macro_use] extern crate rocket;

#[get("/")]
fn hello() -> String {
    format!("Hello world!")
}

#[launch]
fn rocket() -> _ {
    let config = rocket::Config {
        port: 8080,
        log_level: rocket::config::LogLevel::Off,
        ..rocket::Config::debug_default()
    };
    rocket::custom(&config).mount("/", routes![hello])
}

Tide

[package]
name = "tide-hello"
version = "0.1.0"
edition = "2021"

[dependencies]
tide = "0.16.0"
async-std = { version = "1.8.0", features = ["attributes"] }
#[async_std::main]
async fn main() -> Result<(), std::io::Error> {
    let mut app = tide::new();
    app.at("/").get(|_| async { Ok("Hello world!") });
    app.listen("127.0.0.1:8080").await?;
    Ok(())
}

Gotham

[package]
name = "gotham-hello"
version = "0.1.0"
edition = "2021"

[dependencies]
gotham = "0.7.2"
use gotham::state::State;

pub fn say_hello(state: State) -> (State, &'static str) {
    (state, "Hello world!")
}

pub fn main() {
    gotham::start("127.0.0.1:8080", || Ok(say_hello)).unwrap();
}

Ntex

[package]
name = "ntex-hello"
version = "0.1.0"
edition = "2021"

[dependencies]
ntex = { version= "0.7.16", features = ["tokio"] }
use ntex::web;

#[web::get("/")]
async fn index() -> impl web::Responder {
    "Hello, World!"
}

#[ntex::main]
async fn main() -> std::io::Result<()> {
    web::HttpServer::new(|| web::App::new().service(index))
        .bind(("127.0.0.1", 8080))?
        .run()
        .await
}

Poem

[package]
name = "poem-hello"
version = "0.1.0"
edition = "2021"

[dependencies]
poem = "1.3.59"
tokio = { features = ["rt-multi-thread", "macros"] }
use poem::{get, handler, listener::TcpListener, middleware::Tracing, Route, Server};

#[handler]
fn hello() -> String {
    format!("Hello world!")
}

#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
    let app = Route::new().at("/", get(hello)).with(Tracing);
    Server::new(TcpListener::bind("0.0.0.0:8080"))
        .name("hello-world")
        .run(app)
        .await
}

Results

The benchmark results are shown in the following tables (images). For 50, 100, and 150 concurrent connections, each test performed 1,000,000 requests.

50 concurrent benchmark
50 concurrent benchmark
100 concurrent benchmark
100 concurrent benchmark
150 concurrent benchmark
150 concurrent benchmark

Tide is the slowest (12 s for 1 M requests, ~159 K req/s).

Axum is the fastest (can finish 1 M requests in under 6 s).

Resource usage across frameworks is nearly identical.

Winner: Axum

These results reflect a bare‑bones "Hello World" scenario; real‑world projects with more complex logic may see smaller performance differences.

Conclusion

The source code for all benchmarks is available on GitHub: https://github.com/randiekas/rust-web-framework-benchmark . Readers are encouraged to explore the repository and adapt the benchmarks to their own workloads.

References

Author: 万能的大雄

Original article: Rust: The Fastest Rust Web Framework in 2024

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PerformanceRustbenchmarkWeb FrameworkAxumActix
21CTO
Written by

21CTO

21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.