- Simple & Powerful - Minimal boilerplate. If you can write a function, you can write a handler.
- HTTP/1, HTTP/2 & HTTP/3 - Full protocol support out of the box.
- Flexible Routing - Tree-based routing with middleware support at any level.
- Auto TLS - ACME integration for automatic certificate management.
- OpenAPI - First-class OpenAPI support with auto-generated documentation.
- WebSocket & WebTransport - Real-time communication built-in.
- Built on Hyper & Tokio - Production-ready async foundation.
Create a new project:
cargo new hello-salvo && cd hello-salvo
cargo add salvo tokio --features salvo/oapi,tokio/macrosWrite your first app in src/main.rs:
use salvo::prelude::*;
#[handler]
async fn hello() -> &'static str {
"Hello World"
}
#[tokio::main]
async fn main() {
let router = Router::new().get(hello);
let acceptor = TcpListener::new("127.0.0.1:7878").bind().await;
Server::new(acceptor).serve(router).await;
}Run it:
cargo runNo complex traits or generics. Middleware is just a handler:
#[handler]
async fn add_header(res: &mut Response) {
res.headers_mut().insert(header::SERVER, HeaderValue::from_static("Salvo"));
}
Router::new().hoop(add_header).get(hello)Apply middleware to specific route branches:
Router::new()
// Public routes
.push(Router::with_path("articles").get(list_articles))
// Protected routes
.push(Router::with_path("articles").hoop(auth_check).post(create_article).delete(delete_article))Just change #[handler] to #[endpoint]:
#[endpoint]
async fn hello() -> &'static str {
"Hello World"
}Get TLS certificates automatically from Let's Encrypt:
let listener = TcpListener::new("0.0.0.0:443")
.acme()
.add_domain("example.com")
.http01_challenge(&mut router)
.quinn("0.0.0.0:443"); // HTTP/3 supportcargo install salvo-cli
salvo new my_projectSalvo consistently ranks among the fastest Rust web frameworks:
If you find Salvo useful, consider buying me a coffee.
Licensed under either of Apache License 2.0 or MIT license.