Overview
Actix Web is Rust's pre-substrate incumbent: started 2017 on the actix actor
framework, rebuilt over the years into a self-contained web stack with its own HTTP
engine (actix-http), its own middleware model, and years at the top of the
TechEmpower benchmarks. The actor heritage survives only in the name and in
actix-the-crate being an optional companion — modern Actix Web is ordinary async
Rust on Tokio. It is the "Gin of Rust": mature, fast, batteries included, and running
its own stack where axum rides the shared one.
Key points
- Own engine, own contracts:
actix-httpinstead of hyper,App/HttpServerinstead of a tower stack — tower-http middleware doesn't apply; the actix-web ecosystem (actix-cors, actix-session, actix-identity, actix-web-httpauth) fills the same needs in-house. - Familiar handler shape: async fns with extractors (
web::Path,web::Query,web::Json,web::Data<T>for state) andResponderreturns — API-compatible in spirit with axum, different types throughout. - Routing via macros or builders:
#[get("/users/{id}")]attributes orweb::resource("/users/{id}").route(web::get().to(show));web::scopefor prefix grouping. - Middleware is the
Transformtrait: wrap-service factories — more boilerplate than tower layers;middleware::from_fn(like axum's) covers the easy cases now. - The runtime nuance: runs on Tokio but historically via
actix-rtwith a multi-threaded, non-work-stealing model — one single-threaded server instance per core, connections pinned to a worker. That architecture (noSendbounds on handlers' futures, per-workerAppstate factories) is why the benchmarks are good, and the main mental-model difference from axum. - Performance: consistently at or near the top for Rust frameworks; the honest summary is that axum closed most of the gap and both saturate real-world workloads — choose on ecosystem shape, not benchmark deltas.
- Ecosystem posture: the 2020 maintainer crisis (unsafe-code controversy,
original author's departure) is history — a community team has shipped steadily
since; the actor framework
actixremains for stateful in-process components (WebSocket session registries are the classic use — see WebSockets in Rust).
Examples
#[get("/users/{id}")]
async fn show_user(
data: web::Data<AppState>,
path: web::Path<Uuid>,
) -> Result<web::Json<User>, ApiError> {
let user = users::find(&data.pool, *path).await?;
Ok(web::Json(user))
}
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(state.clone()))
.wrap(middleware::Logger::default())
.service(show_user)
})
.bind(("0.0.0.0", 8080))?
.run()
.await?;
Related
- Rust web frameworks — the landscape — parent overview.
- Frameworks × tower/hyper — actix as the "brings its own stack" column.
- Axum deep dive — the shared-substrate alternative.
- REST in Rust — actix in API practice.
- Fiber deep dive — Go's own-stack analog (with a bigger compatibility price than actix pays).