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