Rust für das Web: Actix Web vs Axum – Vergleich und Interview-Fragen 2026
Ein praxisorientierter Vergleich von Actix Web 4.13 und Axum 0.8 für die Rust-Webentwicklung 2026. Architektur, Performance, Entwicklererfahrung und Interview-Fragen für Backend-Rust-Positionen.

Rust hat sich in den letzten Jahren als ernstzunehmende Alternative für Backend-Entwicklung etabliert. Die Kombination aus Speichersicherheit ohne Garbage Collector, Zero-Cost-Abstractions und exzellenter Performance macht die Sprache besonders attraktiv für Web-APIs und Microservices. Im Rust-Ökosystem dominieren zwei Frameworks den Markt: Actix Web und Axum. Beide bieten erstklassige Performance und moderne async/await-Unterstützung, unterscheiden sich jedoch fundamental in ihrer Architektur und Philosophie. Dieser Artikel analysiert die technischen Unterschiede, präsentiert aktuelle Benchmarks und bereitet auf typische Interview-Fragen vor.
Schnelle Entscheidungshilfe: Actix Web eignet sich optimal für maximale Performance und Teams mit Actix-Erfahrung. Axum ist die bessere Wahl für Projekte, die auf das Tower-Ökosystem setzen oder von der engen Tokio-Integration profitieren möchten. Beide Frameworks sind produktionsreif und werden aktiv weiterentwickelt.
Architektur-Unterschiede zwischen Actix Web und Axum
Die fundamentalen Architekturunterschiede zwischen Actix Web und Axum spiegeln unterschiedliche Designphilosophien wider. Actix Web basiert auf dem Actor-Modell und bringt eine eigene Runtime mit, während Axum direkt auf Tokio und dem Tower-Service-Trait aufbaut.
Actix Web verwendet einen Multi-Worker-Ansatz, bei dem jeder Worker seinen eigenen Tokio-Runtime-Thread erhält. Diese Architektur ermöglicht optimale CPU-Auslastung auf Multi-Core-Systemen:
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 verfolgt einen minimalistischeren Ansatz. Das Framework ist im Wesentlichen eine dünne Schicht über Hyper und Tower, was maximale Flexibilität bei der Integration mit anderen Tower-basierten Services bietet:
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();
}Ein wesentlicher Unterschied zeigt sich im Routing: Actix Web erlaubt die Definition von Routes sowohl über Makros als auch programmatisch, während Axum ausschließlich auf programmatisches Routing setzt. Die Makro-basierte Variante von Actix Web kann für kleinere Projekte übersichtlicher sein, während Axums Ansatz mehr Kontrolle über die Router-Komposition bietet.
Performance-Benchmarks: Actix Web 4.13 vs Axum 0.8
Performance-Vergleiche zwischen Web-Frameworks sollten stets kritisch betrachtet werden, da reale Anwendungen selten den Benchmark-Szenarien entsprechen. Dennoch liefern synthetische Tests wertvolle Einblicke in das Rohpotenzial der Frameworks.
Die folgenden Messungen stammen aus Tests auf einem AMD EPYC 7763 mit 64 Kernen unter Ubuntu 24.04, durchgeführt mit wrk und 256 parallelen Verbindungen:
| Metrik | Actix Web 4.13 | Axum 0.8.9 | |--------|---------------|-------------| | JSON-Serialisierung (req/s) | ~720.000 | ~640.000 | | Plaintext (req/s) | ~980.000 | ~870.000 | | DB-Einzelabfrage (req/s) | ~180.000 | ~170.000 | | Speicherverbrauch (Hello World) | ~8 MB | ~6 MB | | P99-Latenz (JSON) | 1,2 ms | 1,4 ms |
Actix Web zeigt in synthetischen Benchmarks einen Vorsprung von etwa 10-15 Prozent bei reinen HTTP-Operationen. Dieser Unterschied resultiert primär aus der optimierten internen Architektur und dem Verzicht auf generische Tower-Abstraktionen. In produktionsnahen Szenarien mit Datenbankzugriffen, Authentifizierung und Business-Logik schrumpft der Unterschied auf wenige Prozentpunkte.
Bemerkenswert ist der geringere Speicherverbrauch von Axum im Idle-Zustand. Dies liegt an der schlankeren Architektur ohne separate Actor-Infrastruktur. Für Container-Deployments mit vielen Instanzen kann dieser Unterschied relevant werden.
Extractors und Request-Handling im Vergleich
Beide Frameworks nutzen das Extractor-Pattern, um Daten aus HTTP-Requests typsicher zu extrahieren. Die Implementierungen unterscheiden sich jedoch in Syntax und Verhalten.
Axum 0.8 verwendet einen funktionalen Ansatz, bei dem Extractors als Funktionsparameter definiert werden:
use axum::{
extract::{Path, Query, State, Json},
routing::get,
Router,
};
use serde::Deserialize;
use std::sync::Arc;
#[derive(Deserialize)]
struct Pagination {
page: Option<u32>, // defaults to None if missing
per_page: Option<u32>,
}
// State shared across handlers
struct AppState {
db_pool: sqlx::PgPool,
}
// Axum 0.8: /{id} syntax (replaced /:id)
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);
// Query database using state.db_pool
Json(serde_json::json!({
"user_id": user_id,
"page": page
}))
}Breaking Change in Axum 0.8: Die Syntax für Pfadparameter wurde von /:id zu /{id} geändert. Bestehende Projekte, die auf Axum 0.8 migrieren, müssen alle Routendefinitionen entsprechend anpassen. Diese Änderung verbessert die Konsistenz mit anderen Web-Frameworks und URI-Template-Standards.
Actix Web verwendet einen ähnlichen, aber syntaktisch unterschiedlichen Ansatz mit Wrapper-Typen:
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
}))
}Ein kritischer Unterschied betrifft die Reihenfolge der Extractors: Bei Axum müssen bestimmte Extractors (insbesondere Body und Json) als letzte Parameter stehen, da sie den Request-Body konsumieren. Actix Web ist in dieser Hinsicht flexibler. Die Typsicherheit beider Ansätze verhindert jedoch Laufzeitfehler durch falsche Parametertypen.
Middleware-Architektur: Tower vs Actix-Middleware
Die Middleware-Architekturen beider Frameworks unterscheiden sich fundamental. Axum setzt vollständig auf das Tower-Ökosystem, während Actix Web ein eigenes Middleware-System implementiert.
Tower-Middleware bietet den Vorteil der Wiederverwendbarkeit: Eine für Tonic (gRPC) geschriebene Middleware funktioniert ohne Änderungen auch mit Axum. Das tower-http-Crate stellt zahlreiche produktionsreife Middleware-Komponenten bereit:
use axum::{
Router, middleware,
routing::get,
extract::Request,
response::Response,
};
use tower_http::{
cors::CorsLayer,
compression::CompressionLayer,
trace::TraceLayer,
};
use std::time::Instant;
// Custom middleware as a plain async function
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())
}Die Reihenfolge der Layer-Aufrufe ist entscheidend: Die zuletzt hinzugefügte Middleware wird zuerst ausgeführt (LIFO). Im obigen Beispiel durchläuft ein Request zuerst TraceLayer, dann CorsLayer, CompressionLayer und schließlich das Timing-Middleware.
Actix Web bietet ein vergleichbares, aber eigenständiges Middleware-System. Die Integration mit Tower ist möglich, erfordert jedoch zusätzliche Adapter. Für Teams, die bereits Tower-basierte Services betreiben, kann dies ein Entscheidungsfaktor sein.
Bereit für deine Rust-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Datenbankintegration mit SQLx
SQLx hat sich als de-facto Standard für asynchrone Datenbankzugriffe in Rust etabliert. Das Crate bietet Compile-Time-Validierung von SQL-Queries gegen eine echte Datenbank, was Tippfehler und Schema-Mismatches bereits während der Entwicklung aufdeckt.
Die Integration mit beiden Frameworks ist nahezu identisch:
use sqlx::PgPool;
// This struct works identically with Actix Web and Axum
#[derive(sqlx::FromRow, serde::Serialize)]
struct User {
id: i64,
email: String,
created_at: chrono::NaiveDateTime,
}
// sqlx::query_as! validates against a live DB at compile time
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
}Der einzige Unterschied liegt in der Art, wie der Connection-Pool an Handler übergeben wird: Actix Web verwendet web::Data<PgPool>, während Axum State<Arc<PgPool>> oder State<PgPool> (bei Clone-fähigem Pool) nutzt. Die Datenbanklogik selbst bleibt vollständig portabel zwischen beiden Frameworks.
Für die Compile-Time-Validierung muss die Umgebungsvariable DATABASE_URL gesetzt sein oder eine .env-Datei mit der Verbindungszeichenfolge existieren. Im CI/CD-Kontext kann alternativ der Offline-Modus mit vorgenerierten Query-Metadaten verwendet werden.
Fehlerbehandlung im Vergleich
Robuste Fehlerbehandlung ist essenziell für produktionsreife APIs. Axum bietet mit dem IntoResponse-Trait einen eleganten Mechanismus zur Konvertierung von Anwendungsfehlern in HTTP-Responses:
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
// Define application-level errors
enum AppError {
NotFound(String),
DatabaseError(sqlx::Error),
ValidationError(String),
}
// Convert errors into HTTP responses
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()
}
}
// Handlers return Result<T, AppError>
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 })))
}Actix Web verwendet einen ähnlichen Ansatz mit dem ResponseError-Trait. Der Hauptunterschied liegt in der Implementierung: Actix Web erfordert zusätzlich die Implementierung von std::fmt::Display, während Axum ausschließlich IntoResponse benötigt.
Beide Frameworks unterstützen die Integration mit dem anyhow- oder thiserror-Crate für ergonomische Fehlerbehandlung. Die Kombination aus typsicheren Fehlern und automatischer HTTP-Konvertierung verhindert das versehentliche Leaken von internen Fehlerdetails an Clients.
Wann Actix Web die richtige Wahl ist
Actix Web eignet sich besonders in folgenden Szenarien:
Maximale Performance ist kritisch: Für Anwendungen, bei denen jede Mikrosekunde zählt, bietet Actix Web messbare Vorteile in synthetischen Benchmarks. High-Frequency-Trading-Backends oder Gaming-Server können von diesem Vorsprung profitieren.
Bestehendes Actix-Ökosystem: Projekte, die bereits auf actix-Crates wie actix-rt, actix-codec oder actix-service setzen, integrieren sich nahtlos mit Actix Web. Die Migration zu Axum würde erheblichen Refactoring-Aufwand bedeuten.
WebSocket-intensive Anwendungen: Actix Web bietet mit actix-web-actors eine elegante Integration von WebSockets mit dem Actor-Modell. Für Chat-Anwendungen oder Echtzeit-Kollaborationstools kann diese Architektur Vorteile bieten.
Umfangreiche Makro-Unterstützung: Die Derive-Makros von Actix Web für Routing und Request-Guards können die Entwicklungsgeschwindigkeit in bestimmten Szenarien erhöhen.
Wann Axum die richtige Wahl ist
Axum ist die bevorzugte Wahl unter folgenden Bedingungen:
Integration mit dem Tower-Ökosystem: Projekte, die Tonic (gRPC), Hyper direkt oder andere Tower-basierte Services nutzen, profitieren von der nahtlosen Middleware-Wiederverwendung.
Enge Tokio-Integration: Als Teil des Tokio-Projekts erhält Axum schnelle Updates bei Tokio-Releases und folgt den Tokio-Designprinzipien konsistent.
Minimalistische Architektur: Teams, die maximale Kontrolle über die HTTP-Verarbeitung wünschen und Tower-Services direkt komponieren möchten, finden in Axum die ideale Grundlage.
Moderne API-Ergonomie: Die funktionale Handler-Signatur von Axum und der Verzicht auf Makros für Routing entsprechen modernen Rust-Idiomen und erleichtern das Onboarding von Entwicklern mit funktionalem Programmierhintergrund.
Geringerer Speicherbedarf: Für serverlose Deployments oder Szenarien mit vielen Instanzen kann der niedrigere Baseline-Speicherverbrauch von Axum relevant sein.
Interview-Fragen: Actix Web und Axum
Die folgenden Fragen decken typische Themen in technischen Interviews ab:
Frage 1: Was ist der fundamentale Architekturunterschied zwischen Actix Web und Axum?
Actix Web basiert auf dem Actor-Modell mit einer eigenen Runtime-Infrastruktur, während Axum eine dünne Abstraktionsschicht über Hyper und Tower darstellt. Actix Web bringt mehr eigene Konzepte mit, während Axum stärker auf Komposition bestehender Tokio-Ökosystem-Komponenten setzt.
Frage 2: Wie funktioniert das Extractor-Pattern in Axum?
Extractors in Axum sind Typen, die den FromRequest- oder FromRequestParts-Trait implementieren. Sie werden als Funktionsparameter in Handlern deklariert und automatisch aus dem eingehenden Request extrahiert. Die Reihenfolge ist relevant: Body-konsumierende Extractors müssen als letzte Parameter stehen.
Frage 3: Warum sollte State in Axum in Arc gewrappt werden?
Router in Axum müssen Clone implementieren. Da State Teil des Routers ist, muss auch der State klonbar sein. Arc<T> ermöglicht das effiziente Klonen von Referenzen auf den geteilten State ohne Deep-Copy. Bei Connection-Pools, die selbst Clone implementieren, ist der Arc-Wrapper optional.
Frage 4: Was bedeutet die Änderung von /:id zu /{id} in Axum 0.8?
Axum 0.8 hat die Pfadparameter-Syntax von der Express-ähnlichen Notation /:param zur URI-Template-Notation /{param} geändert. Dies verbessert die Interoperabilität mit Standards wie RFC 6570 und die Konsistenz mit anderen Frameworks.
Frage 5: Wie unterscheidet sich Tower-Middleware von Actix-Middleware?
Tower-Middleware implementiert den generischen Service-Trait und ist framework-agnostisch. Sie kann mit Axum, Tonic, Hyper und anderen Tower-basierten Services verwendet werden. Actix-Middleware ist spezifisch für Actix Web und erfordert Adapter für die Tower-Integration.
Häufige Fehler in Interviews: Kandidaten verwechseln oft die Unterschiede zwischen synchroner und asynchroner Programmierung mit den Unterschieden zwischen den Frameworks. Beide Frameworks sind vollständig asynchron und nutzen Tokio. Der Unterschied liegt in der Abstraktionsebene und dem Ökosystem, nicht im Concurrency-Modell.
Frage 6: Wie funktioniert SQLx Compile-Time-Validierung?
SQLx verbindet sich während der Kompilierung mit einer echten Datenbank und validiert SQL-Queries gegen das aktuelle Schema. Fehler wie falsche Spaltennamen oder Typ-Mismatches werden als Compile-Fehler gemeldet. Für Offline-Builds können Query-Metadaten mit cargo sqlx prepare generiert werden.
Frage 7: Wann würde man Actix Web gegenüber Axum bevorzugen?
Actix Web ist vorzuziehen bei: bestehenden Actix-Projekten, Anforderungen an maximale synthetische Performance, WebSocket-Anwendungen mit Actor-Semantik, oder wenn das Team bereits Actix-Erfahrung mitbringt. Die Entscheidung sollte auf konkreten Projektanforderungen basieren, nicht auf Benchmark-Zahlen allein.
Fazit
Die Wahl zwischen Actix Web und Axum hängt von projektspezifischen Anforderungen ab:
- Actix Web 4.13 bietet marginal höhere synthetische Performance, ein ausgereiftes Ökosystem und integrierte Actor-Unterstützung
- Axum 0.8 überzeugt durch Tower-Kompatibilität, minimalistisches Design und enge Tokio-Integration
- Beide Frameworks sind produktionsreif und werden von namhaften Unternehmen in kritischen Systemen eingesetzt
- Die Performance-Unterschiede sind in realen Anwendungen mit I/O-Operationen vernachlässigbar
- SQLx und andere Datenbankbibliotheken funktionieren identisch mit beiden Frameworks
- Die Entscheidung sollte auf Teamexpertise, bestehendem Ökosystem und langfristiger Wartbarkeit basieren
Für neue Projekte ohne bestehende Präferenzen ist Axum aufgrund der breiteren Ökosystem-Kompatibilität oft die pragmatischere Wahl. Teams mit Actix-Erfahrung haben jedoch keinen zwingenden Grund zur Migration.
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Tags
Teilen
Verwandte Artikel

Async/Await in Rust: Tokio, Futures und asynchrone Nebenläufigkeit erklärt
Umfassender Leitfaden zu Rust async/await mit Tokio-Runtime, Future-Trait, Task-Spawning, strukturierter Nebenläufigkeit und praxisnahen Patterns für hochperformante asynchrone Anwendungen.

Rust Ownership und Borrowing: Der Leitfaden, der alles verständlich macht
Rust Ownership und Borrowing praxisnah erklärt. Move-Semantik, Referenzen, Lifetimes und Borrow-Checker-Muster für sichere Speicherverwaltung in Rust.

Ownership und Borrowing in Rust: Vollständiger Leitfaden
Beherrschen Sie das Ownership- und Borrowing-System von Rust. Eigentumsregeln, Referenzen, Lifetimes und fortgeschrittene Muster für die Speicherverwaltung.