Rate Limiting
Production-ready rate limiting using Bun’s native Redis client with sliding window algorithm.Overview
Response Headers
Every response includes rate limit info:| Header | Description |
|---|---|
X-RateLimit-Limit | Max requests per window |
X-RateLimit-Remaining | Requests left in current window |
X-RateLimit-Reset | Unix timestamp when window resets |
Rate Limited Response (429)
How It Works
Sliding Window Algorithm
Identifier Selection
Configuration
Environment Examples
| Env | TTL | Max | Use Case |
|---|---|---|---|
| Development | 60 | 1000 | High limit, no impact |
| Staging | 60 | 200 | Moderate testing |
| Production | 60 | 100 | Standard public API |
| Strict | 60 | 20 | Sensitive endpoints |
Endpoint-Specific Limits
Override limits per endpoint in route config:Skip Rate Limiting
Internal service calls can skip rate limiting:Redis Key Schema
| Type | Example Key | TTL |
|---|---|---|
| User | ratelimit:user:usr_abc123 | 60s |
| IP | ratelimit:ip:192.168.1.1 | 60s |
| API Key | ratelimit:apikey:hash_xyz | 60s |
Performance
- Redis O(log N) for sorted set operations
- < 1ms typical latency
- Atomic operations (no race conditions)
- No external calls if Redis unavailable (fail-open by default)
Monitoring
Log Rate Limit Events
Metrics to Track
rate_limit_exceeded_total— Counter of denialsrate_limit_remaining— Gauge of remaining requestsrate_limit_reset_seconds— Time until window reset
Security Considerations
| Concern | Mitigation |
|---|---|
| IP spoofing | Trust X-Forwarded-For from known proxies only |
| API key sharing | Rate limit by user after auth |
| DoS attack | Fail-open (allow) vs fail-closed (deny) |
| Cost | Redis memory: ~1KB per identifier per window |
Best Practices
- Set generous limits — Users shouldn’t hit limits during normal use
- Communicate limits — Document in API docs
- Include headers — Let clients track their usage
- Fail-open — Allow requests if Redis unavailable
- Monitor — Track exceeded events in production