193 releases (81 breaking)

Uses new Rust 2024

0.93.0 Apr 30, 2026
0.91.1 Apr 3, 2026
0.89.3 Mar 18, 2026
0.87.1 Dec 31, 2025
0.1.6 Feb 23, 2020

#27 in HTTP server

Download history 191347/week @ 2026-01-23 118192/week @ 2026-01-30 158535/week @ 2026-02-06 172876/week @ 2026-02-13 113798/week @ 2026-02-20 150339/week @ 2026-02-27 146706/week @ 2026-03-06 152931/week @ 2026-03-13 117161/week @ 2026-03-20 124646/week @ 2026-03-27 130785/week @ 2026-04-03 152898/week @ 2026-04-10 100424/week @ 2026-04-17 122887/week @ 2026-04-24 108631/week @ 2026-05-01 108795/week @ 2026-05-08

482,137 downloads per month
Used in 112 crates (89 directly)

Apache-2.0

2MB
26K SLoC

Salvo

A powerful and simple Rust web framework

English   简体中文   繁體中文

build status build status build status codecov
crates.io Documentation Download unsafe forbidden Rust Version
Website

Features

  • 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.

Quick Start

Create a new project:

cargo new hello-salvo
cd hello-salvo
cargo add salvo tokio --features salvo/oapi,tokio/macros

Write 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 run

Why Salvo?

Middleware = Handler

No 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)

Tree Routing with Middleware

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))

OpenAPI in One Line

Just change #[handler] to #[endpoint]:

#[endpoint]
async fn hello() -> &'static str {
    "Hello World"
}

Auto HTTPS with ACME

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 support

CLI Tool

cargo install salvo-cli
salvo new my_project

Learn More

  • Savhub - Easily manage your AI skills. A platform built with Salvo for organizing and sharing AI capabilities.
  • Palpo - A Matrix server implementation in Rust, powered by Salvo.

Check out the full list of community projects in our ECOSYSTEM.md.

Performance

Salvo consistently ranks among the fastest Rust web frameworks:

Support

If you find Salvo useful, consider buying me a coffee.

License

Licensed under Apache License 2.0.

Dependencies

~21–59MB
~1M SLoC