Rust para la Web: Actix Web vs Axum - Comparativa y Preguntas de Entrevista 2026

Comparativa práctica de Actix Web 4.13 y Axum 0.8 para desarrollo web con Rust en 2026. Arquitectura, rendimiento, experiencia de desarrollo y preguntas de entrevista para puestos backend Rust.

Comparativa de los frameworks web de Rust Actix Web y Axum para desarrollo backend

La adopción de frameworks web en Rust se ha acelerado notablemente en 2026, y dos frameworks dominan los despliegues en producción: Actix Web 4.13 y Axum 0.8. La elección entre ambos afecta todo, desde la incorporación de nuevos miembros al equipo hasta el rendimiento en producción, y la pregunta aparece con frecuencia en las entrevistas técnicas para posiciones backend en Rust.

Marco de decisión rápida

Actix Web 4.13 lidera en rendimiento bruto (10-15% más solicitudes/segundo bajo carga pesada). Axum 0.8 proporciona mejor ergonomía a través de traits async nativos, composabilidad de middlewares Tower e integración más estrecha con Tokio. Para la mayoría de los equipos que inician un nuevo proyecto en 2026, Axum es la opción pragmática por defecto, a menos que requisitos extremos de rendimiento dicten lo contrario.

Diferencias arquitectónicas entre Actix Web y Axum

La divergencia arquitectónica entre estos dos frameworks explica la mayoría de las compensaciones en rendimiento y ergonomía.

Actix Web genera N runtimes Tokio de un solo hilo, uno por núcleo físico. Las tareas se fijan a los hilos sin migración entre ellos. Esto elimina la sobrecarga del work-stealing y el rebote de líneas de caché, lo que explica la ventaja constante en rendimiento bajo carga sostenida.

Axum se ejecuta sobre un único runtime Tokio multihilo con work-stealing. El equipo de Tokio construyó Axum específicamente para demostrar las capacidades del runtime, por lo que cada decisión de diseño optimiza la composabilidad con el ecosistema Tokio en general. Los handlers son funciones async simples, y los middlewares utilizan el trait Service de Tower.

actix_hello.rs - Actix Web minimal serverrust
use actix_web::{web, App, HttpServer, HttpResponse};

async fn health() -> HttpResponse {
    HttpResponse::Ok().json(serde_json::json!({ "status": "ok" }))
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .route("/health", web::get().to(health))
    })
    .bind("0.0.0.0:8080")?
    .run()
    .await
}
axum_hello.rs - Axum minimal serverrust
use axum::{Router, Json, routing::get};
use serde_json::{json, Value};

async fn health() -> Json<Value> {
    Json(json!({ "status": "ok" }))
}

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

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

Ambos ejemplos compilan y se ejecutan, pero las diferencias ya son visibles. Actix Web usa su propia macro #[actix_web::main] y retorna std::io::Result. Axum utiliza el estándar #[tokio::main] y construye las rutas mediante una estructura Router. El handler de Axum retorna un extractor tipado (Json<Value>) en lugar de construir manualmente un HttpResponse.

Benchmarks de rendimiento: Actix Web 4.13 vs Axum 0.8

Los datos de benchmark de TechEmpower Round 22 y pruebas reproducibles de la comunidad muestran un patrón consistente.

| Métrica | Actix Web 4.13 | Axum 0.8.9 | |--------|---------------|-------------| | Serialización JSON (req/s) | ~720,000 | ~640,000 | | Texto plano (req/s) | ~980,000 | ~870,000 | | Consulta BD única (req/s) | ~180,000 | ~170,000 | | Uso de memoria (hello world) | ~8 MB | ~6 MB | | Latencia P99 (JSON) | 1.2 ms | 1.4 ms |

Actix Web mantiene una ventaja de rendimiento del 10-15% en todas las categorías. Axum utiliza ligeramente menos memoria gracias al runtime Tokio compartido. Para dar contexto, ambos frameworks superan al servidor HTTP de la biblioteca estándar de Go por 2-3x y a Node.js por 5-8x en hardware equivalente.

La brecha de rendimiento importa para la distribución de anuncios, pipelines de analítica en tiempo real y pasarelas de trading de alta frecuencia. Para una API REST típica que sirve 10,000 solicitudes/segundo, ambos frameworks están muy por encima del cuello de botella, que será la base de datos o las llamadas a servicios externos.

Extractores y manejo de solicitudes comparados

Los extractores definen cómo los frameworks analizan las solicitudes entrantes. Axum 0.8 realizó mejoras significativas al eliminar #[async_trait] en favor de traits async nativos e introducir OptionalFromRequestParts para un mejor manejo de Option<T>.

axum_extractors.rs - Axum 0.8 extractor patternrust
use axum::{
    extract::{Path, Query, State, Json},
    routing::get,
    Router,
};
use serde::Deserialize;
use std::sync::Arc;

#[derive(Deserialize)]
struct Pagination {
    page: Option<u32>,
    per_page: Option<u32>,
}

struct AppState {
    db_pool: sqlx::PgPool,
}

async fn get_user(
    State(state): State<Arc<AppState>>,
    Path(user_id): Path<i64>,
    Query(pagination): Query<Pagination>,
) -> Json<serde_json::Value> {
    let page = pagination.page.unwrap_or(1);
    Json(serde_json::json!({
        "user_id": user_id,
        "page": page
    }))
}
actix_extractors.rs - Actix Web extractor patternrust
use actix_web::{web, HttpResponse};
use serde::Deserialize;

#[derive(Deserialize)]
struct Pagination {
    page: Option<u32>,
    per_page: Option<u32>,
}

struct AppState {
    db_pool: sqlx::PgPool,
}

async fn get_user(
    state: web::Data<AppState>,
    path: web::Path<i64>,
    query: web::Query<Pagination>,
) -> HttpResponse {
    let user_id = path.into_inner();
    let page = query.page.unwrap_or(1);
    HttpResponse::Ok().json(serde_json::json!({
        "user_id": user_id,
        "page": page
    }))
}

Los extractores de Axum usan desestructuración de tuplas directamente en los parámetros de función. Actix Web envuelve todo en web::Path, web::Query, etc., requiriendo llamadas a .into_inner(). Ambos enfoques son type-safe en tiempo de compilación, pero el de Axum se lee de forma más natural.

Cambio importante en Axum 0.8

Los parámetros de ruta cambiaron de la sintaxis /:id a /{id} en Axum 0.8 (a través de matchit 0.8). Esto se alinea con la sintaxis de rutas de OpenAPI. El escape utiliza llaves dobles: {{ para un { literal.

Arquitectura de middlewares: Tower vs Actix Middleware

La composición de middlewares es donde la diferencia arquitectónica produce el mayor impacto práctico.

Axum utiliza los traits Service y Layer de Tower. Cualquier middleware compatible con Tower funciona con Axum, incluyendo limitadores de velocidad, tracing, compresión y capas de autenticación construidas para otros servicios basados en Tower. Esta composabilidad se extiende más allá del HTTP; el mismo middleware puede envolver servicios gRPC a través de Tonic.

axum_middleware.rs - Tower middleware compositionrust
use axum::{
    Router, middleware,
    routing::get,
    extract::Request,
    response::Response,
};
use tower_http::{
    cors::CorsLayer,
    compression::CompressionLayer,
    trace::TraceLayer,
};
use std::time::Instant;

async fn timing_middleware(
    request: Request,
    next: middleware::Next,
) -> Response {
    let start = Instant::now();
    let response = next.run(request).await;
    let duration = start.elapsed();
    tracing::info!("Request took {:?}", duration);
    response
}

fn build_router() -> Router {
    Router::new()
        .route("/api/data", get(|| async { "ok" }))
        .layer(middleware::from_fn(timing_middleware))
        .layer(CompressionLayer::new())
        .layer(CorsLayer::permissive())
        .layer(TraceLayer::new_for_http())
}

Actix Web usa su propio sistema de middleware con los traits Transform y Service (no los de Tower). Los middlewares del amplio ecosistema Tower requieren adaptadores o reescrituras.

Para equipos ya invertidos en el ecosistema Tower a través de Tonic (gRPC) o Hyper, el middleware de Axum es una ventaja significativa. Para equipos que construyen un servicio HTTP independiente, el sistema de middleware de Actix Web es igualmente capaz, simplemente no es intercambiable.

¿Listo para aprobar tus entrevistas de Rust?

Practica con nuestros simuladores interactivos, flashcards y tests técnicos.

Integración con bases de datos usando SQLx

Ambos frameworks se integran bien con SQLx, el toolkit SQL async-first que valida consultas en tiempo de compilación. El patrón de integración difiere ligeramente.

shared_db.rs - SQLx with compile-time query validationrust
use sqlx::PgPool;

#[derive(sqlx::FromRow, serde::Serialize)]
struct User {
    id: i64,
    email: String,
    created_at: chrono::NaiveDateTime,
}

async fn find_user_by_email(
    pool: &PgPool,
    email: &str,
) -> Result<Option<User>, sqlx::Error> {
    sqlx::query_as!(
        User,
        "SELECT id, email, created_at FROM users WHERE email = $1",
        email
    )
    .fetch_optional(pool)
    .await
}

La capa de base de datos permanece idéntica independientemente del framework elegido. La macro query_as! de SQLx se conecta a una base de datos activa en tiempo de compilación y valida nombres de columnas, tipos y existencia de tablas. Un error tipográfico en el nombre de una columna produce un error de compilación, no un fallo en producción.

Patrones de manejo de errores comparados

El manejo de errores revela filosofías de diseño diferentes. Actix Web utiliza implementaciones del trait ResponseError. Axum se basa en IntoResponse combinado con el tipo Result.

axum_errors.rs - Axum error handling with IntoResponserust
use axum::{
    http::StatusCode,
    response::{IntoResponse, Response},
    Json,
};

enum AppError {
    NotFound(String),
    DatabaseError(sqlx::Error),
    ValidationError(String),
}

impl IntoResponse for AppError {
    fn into_response(self) -> Response {
        let (status, message) = match self {
            AppError::NotFound(msg) => (
                StatusCode::NOT_FOUND, msg
            ),
            AppError::DatabaseError(_) => (
                StatusCode::INTERNAL_SERVER_ERROR,
                "Internal server error".to_string(),
            ),
            AppError::ValidationError(msg) => (
                StatusCode::BAD_REQUEST, msg
            ),
        };
        (status, Json(serde_json::json!({ "error": message })))
            .into_response()
    }
}

async fn get_user(
    axum::extract::Path(id): axum::extract::Path<i64>,
) -> Result<Json<serde_json::Value>, AppError> {
    if id <= 0 {
        return Err(AppError::ValidationError(
            "ID must be positive".to_string()
        ));
    }
    Ok(Json(serde_json::json!({ "id": id })))
}

El enfoque de Axum se compone de forma natural con el operador ? de Rust y el tipo Result. Actix Web logra lo mismo a través de ResponseError, que requiere implementar los traits Display y ResponseError. Ambos funcionan, pero el patrón de Axum resulta más idiomático para desarrolladores Rust acostumbrados al trait From y la propagación de errores.

Cuándo elegir Actix Web sobre Axum

Actix Web sigue siendo la elección correcta en escenarios específicos:

  • Requisitos de rendimiento máximo: Intercambios publicitarios, subastas en tiempo real, pipelines de ingesta analítica donde 10-15% más de req/s justifica la compensación.
  • Aplicaciones con uso intensivo de WebSocket: El soporte WebSocket de Actix Web está probado en batalla en más despliegues de producción. El soporte WebSocket de Axum (vía axum::extract::ws) funciona bien pero tiene un historial de producción más corto.
  • Bases de código Actix Web existentes: La migración de Actix Web 3.x a 4.x es directa. Reescribir a Axum ofrece rendimientos decrecientes para servicios estables.
  • Familiaridad del equipo: Si el equipo ya conoce Actix Web, cambiar de framework por ganancias ergonómicas raramente es rentable a corto plazo.

Cuándo elegir Axum sobre Actix Web

Axum encaja mejor en estos contextos:

  • Nuevos proyectos en 2026: La alineación con el ecosistema Tokio (Tonic, Hyper, Tower) reduce la fricción de integración.
  • Servicios mixtos gRPC y HTTP: Los middlewares Tower funcionan en ambos protocolos sin capas de adaptación.
  • Equipos nuevos en Rust: Los extractores tipados de Axum y los mensajes de error en compilación ofrecen una curva de aprendizaje más suave. La sintaxis /{id} para rutas (alineada con OpenAPI) es inmediatamente familiar.
  • Arquitecturas de microservicios: El trait Service de Tower permite la reutilización de middlewares entre servicios, reduciendo el código repetitivo.

Preguntas de entrevista: Actix Web y Axum para posiciones backend Rust

Las preguntas de entrevista backend Rust cubren cada vez más el conocimiento sobre frameworks web. Estas preguntas aparecen en entrevistas para puestos de ingeniería backend y de sistemas senior.

P: Explicar la diferencia arquitectónica entre los modelos de runtime de Actix Web y Axum.

Actix Web genera un runtime Tokio de un solo hilo por núcleo de CPU. Las tareas se fijan a los hilos, eliminando la sobrecarga del work-stealing. Axum se ejecuta sobre un runtime Tokio multihilo compartido con work-stealing. El modelo de Actix Web reduce la contención de líneas de caché bajo carga pesada, produciendo un rendimiento superior. El modelo de Axum simplifica la gestión de estado compartido ya que todas las tareas comparten un solo runtime.

P: ¿Cómo afecta la eliminación de #[async_trait] en Axum 0.8 a los extractores personalizados?

Axum 0.8 aprovecha los impl Trait nativos en posición de retorno en traits de Rust (estabilizados a finales de 2023). Los extractores personalizados que implementan FromRequestParts o FromRequest ahora definen métodos async directamente sin el atributo #[async_trait]. Esto elimina las asignaciones en el heap de Box<dyn Future> y mejora los tiempos de compilación. Los extractores existentes requieren eliminar la macro y ajustar las implementaciones de traits.

P: Describir en qué se diferencia el middleware Tower del middleware de Actix Web.

Tower define un trait genérico Service<Request> que es agnóstico del protocolo. Una capa de timeout de Tower funciona con HTTP (Axum), gRPC (Tonic) y cualquier protocolo personalizado. El middleware de Actix Web usa los traits Transform y Service específicos de su framework. El impacto práctico: el middleware de Axum es reutilizable en el ecosistema Tower; el middleware de Actix Web es específico del framework.

P: ¿Cómo funciona la validación de consultas en tiempo de compilación de SQLx y cuáles son sus compensaciones?

La macro query_as! de SQLx se conecta a una base de datos PostgreSQL activa durante la compilación. Valida la sintaxis SQL, nombres de columnas, tipos y existencia de tablas. La compensación: la compilación requiere acceso a la base de datos, lo cual complica los pipelines de CI. SQLx proporciona sqlx prepare para generar metadatos de consulta offline, almacenando en caché los resultados de validación en un directorio .sqlx que se incluye en el control de versiones.

P: ¿Cuándo sería técnicamente correcto elegir Actix Web sobre Axum?

Actix Web es la elección correcta cuando el rendimiento sostenido es la restricción principal: distribución de anuncios, ingesta de analítica en tiempo real o pasarelas de trading de alta frecuencia. El modelo de runtime con hilos fijos elimina la sobrecarga del work-stealing, produciendo 10-15% más de req/s bajo carga. Axum es la elección correcta cuando la composabilidad con el ecosistema Tokio importa más que las ganancias marginales de rendimiento, particularmente en arquitecturas de microservicios que usan tanto HTTP como gRPC.

Error común en entrevistas

Los candidatos frecuentemente afirman que un framework es universalmente superior. Las respuestas sólidas reconocen la compensación: Actix Web optimiza el rendimiento, Axum optimiza la composabilidad con el ecosistema. La elección correcta depende de las restricciones del sistema, no de la preferencia personal.

Conclusión

  • Actix Web 4.13 entrega 10-15% más de rendimiento a través de su modelo de runtime con hilos fijos, haciéndolo la elección correcta para servicios de alto rendimiento sensibles a la latencia
  • Axum 0.8 proporciona mejor ergonomía con traits async nativos, sintaxis /{id} para rutas y compatibilidad completa con middlewares Tower en HTTP y gRPC
  • Ambos frameworks usan la misma capa de base de datos (SQLx con validación en compilación), por lo que la elección no afecta los patrones de acceso a datos
  • Para nuevos proyectos web en Rust en 2026 sin requisitos extremos de rendimiento, la alineación de Axum con el ecosistema Tokio, Tonic y Tower reduce el costo de mantenimiento a largo plazo
  • Las preguntas de entrevista sobre este tema evalúan la comprensión de modelos de runtime, arquitectura de middlewares y razonamiento sobre compensaciones, no la preferencia por un framework
  • Prepararse para entrevistas de Rust requiere comprender las decisiones arquitectónicas de ambos frameworks, no solo la sintaxis de sus APIs

¡Empieza a practicar!

Pon a prueba tu conocimiento con nuestros simuladores de entrevista y tests técnicos.

Etiquetas

#rust
#actix-web
#axum
#web-framework
#backend
#comparison

Compartir

Artículos relacionados