Introduction
Volter is a production-grade, async-first web framework for Rust. It follows the
same architectural principles as tower — every component is a Service or
a Layer, making the framework naturally composable.
Why Volter?
Rust has several excellent web frameworks. Volter was built for teams that want:
- No panics in request paths — deny-level lints (
unwrap_used,expect_used,panic,indexing_slicing) are enforced in every library crate. - Tower-native composition — use any
tower::Layerortower::Servicewithout adapters. Middleware, routing, and handlers all speak the sameServiceprotocol. - Compile-time safety — wrong state type? It won’t compile. Missing extractor? It won’t compile.
- No macros required — the core API is pure Rust. Derive macros and attribute macros are optional sugar.
Design Principles
-
Everything is a Service.
Router<S>implementstower::Service<Request>. Middleware istower::Layer. Handlers becomeServices viaHandlerService. -
Rejection is a first-class concept. Every extractor defines its own rejection type that implements
IntoResponse. A missing query parameter and an invalid JSON body produce different, predictable HTTP responses. -
State is typed. Application state is checked at compile time. If your handler extracts
State<AppConfig>, you must provide aRouter<AppConfig>. -
Panics are caught. Wrap your router with
CatchPanicLayerto turn handler panics into500 Internal Server Errorresponses, keeping the server alive.
Crate Layout
Volter is organised as a set of focused crates, all re-exported through the
top-level volter crate:
| Crate | Purpose |
|---|---|
volter | Meta-crate — re-exports everything |
volter-core | Core traits: Handler, FromRequest, IntoResponse, State |
volter-router | Router, MethodRouter, route construction |
volter-extract | Extractors: Json, Query, Path, Extension |
volter-middleware | Built-in middleware: TraceLayer, CorsLayer, etc. |
volter-ws | WebSocket support |
volter-macros | Optional derive and attribute macros |
volter-testing | TestClient for integration tests |
volter-cli | CLI tool for scaffolding (volter new) |
Quick Start
use tokio::net::TcpListener;
use volter::{get, serve, Router};
async fn hello() -> &'static str {
"Hello, World!"
}
#[tokio::main]
async fn main() -> Result<(), volter::BoxError> {
let app = Router::new().route("/", get(hello));
let listener = TcpListener::bind("0.0.0.0:3000").await?;
serve(listener, app).await
}