touch-ratelimit
A composable, extensible rate limiting crate for Rust.
touch-ratelimit provides clean building blocks for implementing rate limiting
in Rust applications using a clear separation of concerns:
- Algorithms – how rate limiting works (e.g. token bucket)
- Stores – where rate limiting state lives
- Middleware – how rate limiting is applied to requests
- Adapters – framework integrations (e.g. Axum)
The crate is designed to be framework-agnostic, storage-agnostic, and algorithm-agnostic, making it easy to extend without rewriting core logic.
Features
- Token bucket rate limiting algorithm
- In-memory storage backend
- Tower-based middleware
- Axum integration
- Designed for extension (Redis, additional algorithms planned)
Installation
Core crate
[]
= "0.1"
With Axum integration
[]
= { = "0.1", = ["axum"] }
= "0.8"
= { = "1", = ["full"] }
Example: Axum
use ;
use ;
async
Requests exceeding the configured rate limit receive:
HTTP 429 Too Many Requests
Core Concepts
RateLimiter
A RateLimiter represents the rate-limiting logic for a single identity
(e.g. one user, one IP address, one API key).
Examples include:
- Token bucket
- Sliding window (planned)
- Leaky bucket (planned)
Each RateLimiter instance is stateful and is not shared across identities.
RateLimitStore
A RateLimitStore manages many RateLimiter instances and maps them to
request keys.
Responsibilities include:
- Creating rate limiters for new keys
- Handling concurrency
- Owning rate-limiting state
The store is responsible for where and how state is stored.
Middleware
Middleware enforces rate limits before forwarding requests to the inner service.
The core middleware is built on Tower and is framework-agnostic. Framework adapters (e.g. Axum) are thin wrappers around this middleware.
Storage Behavior (Important)
The default InMemoryStore keeps all rate-limiting state inside the
application’s memory.
This means:
- State is lost on restart
- State is not shared across processes
- Each server instance enforces limits independently
This is suitable for:
- Development
- Single-instance deployments
- Edge or sidecar setups
Distributed stores (e.g. Redis) can be added without changing middleware or algorithms.
Key Extraction
The Axum adapter identifies requests using the x-forwarded-for header by
default.
If the header is missing or invalid, rate limiting is skipped for that request.
This behavior is useful when running behind a reverse proxy or load balancer.
Extensibility
The crate is designed so new components can be added independently:
- New algorithms can implement
RateLimiter - New storage backends can implement
RateLimitStore - New framework adapters can be built on top of the core middleware
No changes to existing middleware are required.