| Crates.io | axum-governor |
| lib.rs | axum-governor |
| version | 1.0.2 |
| created_at | 2025-09-04 14:57:22.670276+00 |
| updated_at | 2025-09-04 14:57:22.670276+00 |
| description | Rate limiting middleware for Axum, powered by lazy-limit and unrelated to governor etc. |
| homepage | |
| repository | https://github.com/canmi21/axum-governor |
| max_upload_size | |
| id | 1824328 |
| size | 50,715 |
Axum-Governor is a rate-limiting middleware for Axum, designed to enforce request limits based on client IP addresses. It is powered by the modern, Rust 2024-compliant, and async-first lazy-limit library, offering robust performance, flexible configuration, and built-in memory management to prevent crashes under high load. Note: Despite the name, axum-governor is not related to the governor, tower-governor, or actix-governor crates. The name "governor" is used due to historical naming conventions in rate-limiting libraries, where "xxx-governor" typically denotes rate-limiting middleware.
If you are looking for the governor crate or its derivatives, please visit their respective repositories:
Axum-Governor leverages the lazy-limit library, a modern rate-limiting solution built with Rust 2024 and Tokio for asynchronous, high-performance applications. Unlike traditional rate-limiting libraries, lazy-limit prioritizes service availability over strict enforcement in extreme conditions. Its core philosophy is "running is better than crashing."
real crate to accurately identify client IP addresses, ensuring reliable rate limiting.lazy-limit sacrifices strict rate-limiting enforcement to keep the service running, avoiding crashes.tower::Layer, making it easy to integrate with Axum and other Tower-based frameworks.The underlying lazy-limit library is designed with modern Rust practices and offers several advantages over traditional rate-limiting libraries:
lazy-limit triggers aggressive cleanup of older records. While this may relax strict rate-limiting for some requests, it ensures the service remains operational, avoiding crashes.This approach ensures that even in worst-case scenarios, your service has a better chance of staying online rather than crashing due to memory exhaustion.
Add the following to your Cargo.toml:
[dependencies]
axum-governor = "1"
lazy-limit = "1"
tokio = { version = "1", features = ["full"] }
real = { version = "0.1", features = ["axum"] }
axum = "0.8"
tower = "0.5"
http = "1"
tracing = "0.1"
[dev-dependencies]
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
Ensure you have the required dependencies for lazy-limit and Tokio.
Before starting your Axum application, initialize the rate limiter using the lazy_limit::init_rate_limiter! macro. This sets up global and route-specific rate-limiting rules.
use lazy_limit::{init_rate_limiter, Duration, RuleConfig};
use tokio::main;
#[tokio::main]
async fn main() {
init_rate_limiter!(
default: RuleConfig::new(Duration::seconds(1), 5), // 5 req/s globally
max_memory: Some(64 * headed4 * 1024), // 64MB max memory
routes: [
("/api/login", RuleConfig::new(Duration::minutes(1), 3)), // 3 req/min
("/api/public", RuleConfig::new(Duration::seconds(1), 10)), // 10 req/s
("/api/premium", RuleConfig::new(Duration::seconds(1), 20)), // 20 req/s
]
).await;
// Your Axum application setup goes here
}
Add the RealIpLayer and GovernorLayer to your Axum router. The RealIpLayer must be added before the GovernorLayer to ensure client IP addresses are available.
use axum::{Router, routing::get, Server};
use axum_governor::{GovernorLayer, GovernorConfig};
use real::RealIpLayer;
use std::net::SocketAddr;
use tower::ServiceBuilder;
async fn handler() -> &'static str {
"Hello, world!"
}
#[tokio::main]
async fn main() {
// Initialize rate limiter (as shown above)
init_rate_limiter!(
default: RuleConfig::new(Duration::seconds(1), 5),
routes: [
("/api/login", RuleConfig::new(Duration::minutes(1), 3)),
]
).await;
// Create the Axum router
let app = Router::new()
.route("/", get(handler))
.layer(
ServiceBuilder::new()
.layer(RealIpLayer::default()) // Extracts the real IP
.layer(GovernorLayer::default()) // Applies rate limiting
);
// Start the server
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
axum::serve(listener, app.into_make_service_with_connect_info::<SocketAddr>())
.await
.unwrap();
}
To ignore global rate limits and apply only route-specific rules, use the GovernorConfig with override_mode set to true:
let override_limiter = ServiceBuilder::new()
.layer(RealIpLayer::default())
.layer(GovernorLayer::new(GovernorConfig::new().override_mode(true)));
let premium_routes = Router::new()
.route("/api/premium", get(premium_handler))
.layer(override_limiter);
The included examples/demo.rs provides a comprehensive example showcasing various rate-limiting scenarios:
/api/login./api/premium.Run the demo with:
cargo run --example demo
The demo outputs curl commands to test rate limits, such as:
# Test global limit (5 req/s)
for i in {1..6}; do curl -w '%{http_code}\n' http://127.0.0.1:3000/; done
# Test route-specific limit (3 req/min)
for i in {1..4}; do curl -w '%{http_code}\n' http://127.0.0.1:3000/api/login; done
tower::Layer interface for easy setup.axum-governor/
├── examples/
│ └── demo.rs # Example showcasing rate-limiting scenarios
├── src/
│ ├── config.rs # Configuration for the rate limiter
│ ├── layer.rs # Tower Layer implementation
│ ├── lib.rs # Main library entry point and exports
│ ├── middleware.rs # Rate-limiting middleware logic
├── Cargo.toml # Project metadata and dependencies
├── LICENSE # MIT License
├── README.md # This file
lazy_limit::RuleConfig.init_rate_limiter! macro.override_mode in GovernorConfig to ignore global limits for specific routes.Example configuration:
init_rate_limiter!(
default: RuleConfig::new(Duration::seconds(1), 5),
max_memory: Some(32 * 1024 * 1024), // 32MB
routes: [
("/api/login", RuleConfig::new(Duration::minutes(1), 3)),
]
).await;
Run the included tests to verify functionality:
cargo test --all
The tests cover:
init_rate_limiter! will panic.RealIpLayer must be added before GovernorLayer to provide client IP addresses.Contributions are welcome! Please submit issues or pull requests to the GitHub repository.
git checkout -b feature/your-feature).git commit -m "Add your feature").git push origin feature/your-feature).This project is licensed under the MIT License. See the LICENSE file for details.
For questions or support, please open an issue on the GitHub repository.
Axum-Governor is built on top of the excellent lazy-limit library, which provides the core rate-limiting functionality. Thanks to the Rust and Axum communities for their contributions to the ecosystem!