Camber is opinionated async Rust for IO-bound services on top of Tokio.
In development, publicly usable, and actively dogfooded.
Camber is a library and project tool for the large middle of Rust services that are IO-bound, not scheduler experiments.
Install
Quick Start
Build HTTP services without extractors, Tower, or #[tokio::main]. Async handlers on a Tokio core.
use RuntimeError;
use ;
Use http::serve(...) by itself for the default case. Wrap it in runtime::builder().run(...) only when you need runtime configuration such as worker counts, shutdown timeouts, or registered resources.
Docs
- Vision
- Tokio/Axum to Camber
- Go to Camber
- Proxy Quickstart
- Cross-Compilation
- Reference
- Runtime Reference
- HTTP Reference
- Middleware Reference
- HTTP Client Reference
- Tasks and Channels Reference
- Error Reference
- Config Reference
- TLS Reference
- Net Reference
- Resource Reference
- Scheduling Reference
- Secret Reference
- Signals and Shutdown Reference
- Time Reference
- Logging Reference
If you're evaluating Camber as a library, start with Tokio/Axum to Camber or the Reference.
The README is the overview. docs/reference/ and docs.rs are the exhaustive public surface.
Reverse Proxy (Homelab / WIP)
Config-driven reverse proxy with auto-TLS and health checks. Suited for homelab and internal deployments. Not yet a production edge replacement.
= "0.0.0.0:443"
[]
= true
= "admin@example.com"
[[]]
= "jellyfin.example.com"
= "http://192.168.1.10:8096"
[[]]
= "immich.example.com"
= "http://192.168.1.10:2283"
[[]]
= "grafana.example.com"
= "http://192.168.1.10:3000"
= "/api/health"
Full setup guide: Proxy Quickstart
Middleware
use ;
router.use_middleware;
router.use_middleware;
router.use_middleware;
Auth is just middleware:
use ;
router.use_middleware;
If middleware needs request data after .await, copy out owned data before entering async move.
For normal HTTP handlers, middleware wraps the full owned Request and Response.
For gRPC and proxy_stream, middleware acts as a request gate before streaming begins.
WebSocket & SSE
router.ws;
router.get_sse;
For generic chunked responses, use StreamResponse::new() for the default buffer or
StreamResponse::with_buffer(status, cap) when you need explicit backpressure tuning.
HTTP Client
use http;
let resp = get.await?;
let resp = post_json.await?;
let resp = put.await?;
let resp = delete.await?;
let resp = patch_json.await?;
let resp = client.retries.get.await?;
Cookies
let session = req.cookie;
let resp = text?.set_cookie;
File Uploads
router.post;
Database
use PgPool;
let pool = connect.await?;
// In a handler:
let user =
.bind
.fetch_one
.await?;
Camber does not wrap database drivers. Use sqlx or your preferred ORM directly inside handlers and background tasks.
Observability
use otel;
use circuit_breaker;
router.use_middleware;
let protected = wrap
.failure_threshold
.cooldown
.build;
License
Dual-licensed under MIT and Apache 2.0.