Actix-web Core Knowledge
SkillAI & modelsActix-web Rust web framework. Covers routing, extractors, middleware, state management, and WebSocket. Use for high-performance Rust APIs.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Actix-web Core Knowledge skill
What this skill tells your AI
The instructions your AI receives, as published by claude-dev-suite/claude-dev-suite in skills/backend-frameworks/actix-web/SKILL.md and read by ahel’s review.
Full Reference: See advanced.md for custom timing middleware, authentication middleware, custom error types, WebSocket actors, and graceful shutdown patterns.
Deep Knowledge: Use
mcp__documentation__fetch_docswith technology:actix-webfor comprehensive documentation.
Basic Setup
# Cargo.toml
[dependencies]
actix-web = "4"
actix-rt = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
use actix_web::{web, App, HttpServer, HttpResponse, Responder};
async fn hello() -> impl Responder {
HttpResponse::Ok().body("Hello, World!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/", web::get().to(hello))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
Route Macros
use actix_web::{get, post, web, HttpResponse, Responder};
#[get("/users/{id}")]
async fn get_user(path: web::Path<u32>) -> impl Responder {
let id = path.into_inner();
HttpResponse::Ok().json(serde_json::json!({ "id": id }))
}
#[post("/users")]
async fn create_user(body: web::Json<CreateUser>) -> impl Responder {
HttpResponse::Created().json(body.into_inner())
}
// Register with App
App::new()
.service(get_user)
.service(create_user)
Extractors
| Extractor | Purpose |
|---|---|
web::Path<T> | URL path parameters |
web::Query<T> | Query string |
web::Json<T> | JSON body |
web::Form<T> | Form data |
web::Data<T> | Application state |
Application State
struct AppState {
db_pool: Pool<Postgres>,
}
#[get("/users")]
async fn list_users(data: web::Data<AppState>) -> impl Responder {
let users = sqlx::query_as!(User, "SELECT * FROM users")
.fetch_all(&data.db_pool)
.await?;
HttpResponse::Ok().json(users)
}
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(state.clone()))
.service(list_users)
})
Built-in Middleware
use actix_web::middleware::{Logger, Compress, NormalizePath};
App::new()
.wrap(Logger::default())
.wrap(Compress::default())
.wrap(NormalizePath::trim())
Health Checks
#[get("/health")]
async fn health() -> impl Responder {
HttpResponse::Ok().json(serde_json::json!({ "status": "healthy" }))
}
#[get("/ready")]
async fn ready(data: web::Data<AppState>) -> impl Responder {
match data.db_pool.acquire().await {
Ok(_) => HttpResponse::Ok().json(serde_json::json!({
"status": "ready",
"database": "connected"
})),
Err(_) => HttpResponse::ServiceUnavailable().json(serde_json::json!({
"status": "not ready"
})),
}
}
When NOT to Use This Skill
- Axum projects - Axum is more ergonomic with Tower ecosystem
- Rocket projects - Rocket has better compile-time guarantees
- Warp projects - Warp uses filters for composition
- Simple CLI tools - No web server needed
- Embedded systems - Too heavy for resource-constrained devices
Anti-Patterns
| Anti-Pattern | Why It's Bad | Solution |
|---|---|---|
.clone() on every request | Performance overhead | Use web::Data<Arc<T>> for shared state |
| Blocking I/O in async handlers | Blocks executor threads | Use web::block() for blocking operations |
| Not using extractors | Manual parsing is error-prone | Use Json, Path, Query extractors |
Missing #[actix_web::main] | Manual runtime setup | Use macro for simple setup |
| Global mutable state | Data races | Use Mutex or RwLock with web::Data |
| No custom error types | Generic error messages | Implement ResponseError trait |
Quick Troubleshooting
| Problem | Diagnosis | Fix |
|---|---|---|
| "Cannot move out of borrowed content" | Ownership issue | Clone data or use web::Data<Arc<T>> |
| Handler not found (404) | Route not registered | Check .service() or .route() calls |
| JSON parsing fails | Wrong content-type | Ensure client sends Content-Type: application/json |
| Slow performance | Blocking I/O | Wrap blocking code in web::block() |
| WebSocket connection closes | Missing ping/pong | Implement heartbeat mechanism |
| State not accessible | Not added to app | Use .app_data() when building app |
Checklist
- CORS properly configured
- Authentication middleware
- Custom error handling
- Request logging (Logger middleware)
- Health/readiness endpoints
- Graceful shutdown
- Connection pooling for database
- Input validation
- Rate limiting (actix-ratelimit)
Reference Documentation
Signals
- GitHub stars
- 33
- Forks
- 6
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
actix-web- Source
- github.com/claude-dev-suite/claude-dev-suite