Axum vs Actix Web 2026: Qual Framework Rust? | Rust Brasil

Axum vs Actix Web: comparação completa de frameworks web Rust. Arquitetura, performance, middleware e quando usar cada um em 2026.

Introdução

Quando se trata de desenvolvimento web em Rust, dois frameworks dominam o cenário: Axum e Actix Web. Ambos são maduros, performáticos e amplamente utilizados em produção, mas possuem filosofias de design bastante distintas. Se você está buscando o melhor framework web de Rust em 2026, esta comparação vai ajudá-lo a decidir.

Actix Web surgiu em 2017, inspirado no modelo de atores do Akka (Scala), e rapidamente se tornou o framework web mais popular de Rust — liderando benchmarks do TechEmpower por anos consecutivos. Ele oferece um ecossistema completo com middleware integrado, suporte a WebSocket e extensa documentação.

Axum foi lançado em 2021 pela equipe do Tokio e adota uma abordagem diferente: ao invés de criar abstrações próprias, ele se apoia inteiramente no ecossistema Tower (Service + Layer) e Hyper. O resultado é um framework mais enxuto, composável e que se integra nativamente com tudo que já existe no ecossistema Tokio.

Neste artigo, vamos comparar os dois em profundidade para ajudá-lo a escolher o melhor para seu próximo projeto.

Tabela Comparativa

CaracterísticaAxumActix Web
Primeira versão20212017
MantenedorEquipe TokioComunidade
RuntimeTokio (obrigatório)Tokio (padrão)
ModeloTower ServicesActor Model (parcial)
MiddlewareTower LayersTransform / Middleware traits
ExtractorsGenéricos via FromRequestTrait FromRequest própria
WebSocketVia axum::extract::wsIntegrado
Tipagem de rotasForte (compile-time)Forte (compile-time)
Performance (TechEmpower)Top 10Top 5
Downloads (crates.io)~40M+~55M+
Curva de aprendizadoModeradaModerada

Dependências no Cargo.toml

Para Axum:

[dependencies]
axum = "0.8"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tower-http = { version = "0.6", features = ["cors", "trace"] }
tracing = "0.1"
tracing-subscriber = "0.3"

Para Actix Web:

[dependencies]
actix-web = "4"
actix-rt = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
env_logger = "0.11"
log = "0.4"

Comparação de Código: API REST Básica

Vamos implementar a mesma API — um CRUD simples de tarefas — nos dois frameworks para comparar a ergonomia.

Hello World com Axum

use axum::{routing::get, Router};

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/", get(|| async { "Olá, Axum!" }));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
        .await
        .unwrap();
    axum::serve(listener, app).await.unwrap();
}

Hello World com Actix Web

use actix_web::{web, App, HttpServer, HttpResponse};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .route("/", web::get().to(|| async {
                HttpResponse::Ok().body("Olá, Actix Web!")
            }))
    })
    .bind("0.0.0.0:3000")?
    .run()
    .await
}

Endpoint com JSON e Extractor

Vamos criar um endpoint POST que recebe e retorna JSON.

Axum:

use axum::{routing::post, extract::Json, Router};
use serde::{Deserialize, Serialize};

#[derive(Deserialize)]
struct CriarTarefa {
    titulo: String,
    descricao: Option<String>,
}

#[derive(Serialize)]
struct Tarefa {
    id: u64,
    titulo: String,
    descricao: Option<String>,
    concluida: bool,
}

async fn criar_tarefa(Json(payload): Json<CriarTarefa>) -> Json<Tarefa> {
    let tarefa = Tarefa {
        id: 1,
        titulo: payload.titulo,
        descricao: payload.descricao,
        concluida: false,
    };
    Json(tarefa)
}

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/tarefas", post(criar_tarefa));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
        .await
        .unwrap();
    axum::serve(listener, app).await.unwrap();
}

Actix Web:

use actix_web::{web, App, HttpServer, HttpResponse};
use serde::{Deserialize, Serialize};

#[derive(Deserialize)]
struct CriarTarefa {
    titulo: String,
    descricao: Option<String>,
}

#[derive(Serialize)]
struct Tarefa {
    id: u64,
    titulo: String,
    descricao: Option<String>,
    concluida: bool,
}

async fn criar_tarefa(payload: web::Json<CriarTarefa>) -> HttpResponse {
    let tarefa = Tarefa {
        id: 1,
        titulo: payload.titulo.clone(),
        descricao: payload.descricao.clone(),
        concluida: false,
    };
    HttpResponse::Ok().json(tarefa)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .route("/tarefas", web::post().to(criar_tarefa))
    })
    .bind("0.0.0.0:3000")?
    .run()
    .await
}

Estado Compartilhado

Axum utiliza State extractor integrado ao Router:

use axum::{extract::State, routing::get, Json, Router};
use std::sync::Arc;
use tokio::sync::RwLock;

type Db = Arc<RwLock<Vec<String>>>;

async fn listar(State(db): State<Db>) -> Json<Vec<String>> {
    let dados = db.read().await;
    Json(dados.clone())
}

#[tokio::main]
async fn main() {
    let db: Db = Arc::new(RwLock::new(vec![]));

    let app = Router::new()
        .route("/itens", get(listar))
        .with_state(db);

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
        .await
        .unwrap();
    axum::serve(listener, app).await.unwrap();
}

Actix Web utiliza web::Data:

use actix_web::{web, App, HttpServer, HttpResponse};
use std::sync::RwLock;

struct AppState {
    itens: RwLock<Vec<String>>,
}

async fn listar(data: web::Data<AppState>) -> HttpResponse {
    let itens = data.itens.read().unwrap();
    HttpResponse::Ok().json(itens.clone())
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let state = web::Data::new(AppState {
        itens: RwLock::new(vec![]),
    });

    HttpServer::new(move || {
        App::new()
            .app_data(state.clone())
            .route("/itens", web::get().to(listar))
    })
    .bind("0.0.0.0:3000")?
    .run()
    .await
}

Middleware

Axum usa Tower Layers diretamente:

use axum::{Router, routing::get, middleware};
use tower_http::trace::TraceLayer;
use tower_http::cors::CorsLayer;

let app = Router::new()
    .route("/", get(|| async { "ok" }))
    .layer(TraceLayer::new_for_http())
    .layer(CorsLayer::permissive());

Actix Web usa seu próprio sistema de middleware:

use actix_web::{App, HttpServer, web, middleware};
use actix_cors::Cors;

HttpServer::new(|| {
    App::new()
        .wrap(middleware::Logger::default())
        .wrap(Cors::permissive())
        .route("/", web::get().to(|| async { "ok" }))
})

Performance e Benchmarks

Ambos os frameworks são extremamente rápidos. Nos benchmarks do TechEmpower Framework Benchmarks (Round 22), ambos aparecem consistentemente entre os 10 mais rápidos do mundo, competindo com frameworks em C e C++.

Números aproximados (requisições/segundo em JSON serialization):

FrameworkReq/s (aprox.)
Actix Web~700.000+
Axum~650.000+
Express (Node.js)~80.000
FastAPI (Python)~15.000

A diferença de performance entre Axum e Actix Web é marginal na maioria dos casos de uso reais. Actix Web historicamente tem uma leve vantagem em benchmarks sintéticos, mas na prática, o gargalo será o banco de dados, rede ou lógica de negócio — não o framework.

Ambos utilizam Tokio como runtime async por padrão, o que significa que a base de I/O assíncrono é a mesma. Para uma compreensão mais aprofundada do Tokio, veja nosso Guia Completo do Tokio.

Ecossistema e Comunidade

Axum

  • Vantagem principal: integração total com o ecossistema Tower/Tokio
  • Middleware do Tower funciona diretamente (rate limiting, timeout, compression)
  • Mantido oficialmente pela equipe Tokio — garantia de compatibilidade
  • Crescimento acelerado: já é o framework mais popular para novos projetos
  • Excelente integração com tracing para observabilidade

Actix Web

  • Vantagem principal: ecossistema próprio maduro e completo
  • actix-files, actix-cors, actix-session, actix-identity — tudo integrado
  • Comunidade grande e documentação extensa
  • Usado em produção por empresas como Microsoft, Cloudflare e outras

Quando Escolher Cada Um

Escolha Axum quando:

  • Você já usa ou planeja usar Tokio extensivamente
  • Deseja máxima composabilidade com o ecossistema Tower
  • Prefere um design mais idiomático e alinhado com traits padrão do Rust
  • Está iniciando um projeto novo e quer seguir a tendência do ecossistema
  • Precisa integrar com tonic (gRPC) — ambos são do ecossistema Tokio

Escolha Actix Web quando:

  • Precisa de um ecossistema completo com muitos plugins oficiais
  • Tem um projeto existente em Actix Web que funciona bem
  • Precisa de WebSocket com API mais ergonômica out-of-the-box
  • Valoriza documentação extensa e muitos exemplos disponíveis
  • Precisa do máximo throughput em benchmarks sintéticos

Ambos são boas escolhas quando:

  • Você precisa de uma API REST de alta performance
  • Precisa de type safety em tempo de compilação
  • Trabalha com equipes que conhecem Rust

Guia de Migração: Actix Web para Axum

Se você está considerando migrar de Actix Web para Axum, aqui estão os pontos principais:

1. Handlers

// Actix Web: retorna HttpResponse
async fn handler() -> HttpResponse {
    HttpResponse::Ok().json(dados)
}

// Axum: retorna impl IntoResponse
async fn handler() -> Json<Dados> {
    Json(dados)
}

2. Extractors

// Actix Web
async fn handler(
    path: web::Path<(u64,)>,
    query: web::Query<Filtro>,
    body: web::Json<Payload>,
) -> HttpResponse { ... }

// Axum
async fn handler(
    Path(id): Path<u64>,
    Query(filtro): Query<Filtro>,
    Json(payload): Json<Payload>,
) -> impl IntoResponse { ... }

3. Estado

// Actix Web: web::Data<T>
async fn handler(data: web::Data<AppState>) -> HttpResponse { ... }

// Axum: State<T>
async fn handler(State(state): State<AppState>) -> impl IntoResponse { ... }

4. Rotas

// Actix Web
App::new()
    .route("/usuarios/{id}", web::get().to(obter_usuario))

// Axum
Router::new()
    .route("/usuarios/{id}", get(obter_usuario))

A migração geralmente é tranquila, pois ambos seguem padrões similares. O maior trabalho será adaptar middleware customizado.

Conclusão

Tanto Axum quanto Actix Web são excelentes escolhas para desenvolvimento web em Rust. A tendência atual do ecossistema aponta para o Axum como a escolha padrão para novos projetos, principalmente pela integração nativa com Tokio e Tower. No entanto, Actix Web continua sendo uma opção sólida e battle-tested, especialmente se você já tem projetos funcionando nele.

A recomendação prática: para novos projetos, comece com Axum. Para projetos existentes em Actix Web, não há urgência em migrar — o framework continua ativo e performático. Para uma visão mais ampla do ecossistema web em Rust, confira nosso artigo sobre Rust para Desenvolvimento Web.

Veja Também


Se você trabalha com web frameworks em outras linguagens, confira também: