#web-framework #async #framework #web-server

salvo_extra

Salvo is a powerful web framework that can make your work easier

204 releases (86 breaking)

Uses new Rust 2024

0.89.1 Feb 3, 2026
0.88.1 Jan 8, 2026
0.87.1 Dec 31, 2025
0.85.0 Nov 24, 2025
0.1.6 Feb 23, 2020

#734 in HTTP server

Download history 1676/week @ 2025-10-26 1536/week @ 2025-11-02 17526/week @ 2025-11-09 34760/week @ 2025-11-16 44785/week @ 2025-11-23 30255/week @ 2025-11-30 44274/week @ 2025-12-07 43212/week @ 2025-12-14 45445/week @ 2025-12-21 39236/week @ 2025-12-28 36916/week @ 2026-01-04 32524/week @ 2026-01-11 42407/week @ 2026-01-18 54779/week @ 2026-01-25 40712/week @ 2026-02-01 43277/week @ 2026-02-08

182,625 downloads per month
Used in 45 crates (2 directly)

MIT/Apache

1MB
19K 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

Performance

Salvo consistently ranks among the fastest Rust web frameworks:

Support

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

License

Licensed under either of Apache License 2.0 or MIT license.

Dependencies

~23–43MB
~668K SLoC