What Are Common API Rate Limiting Strategies?
Compare token bucket, fixed window, and sliding window rate limiting, plus how to signal limits with 429 and headers.
Expected Interview Answer
API rate limiting caps how many requests a client can make in a given time window, most commonly implemented with token bucket, fixed window, or sliding window log algorithms, to protect backend capacity and ensure fair usage across clients.
The token bucket algorithm gives each client a bucket that refills with tokens at a steady rate up to a maximum capacity, and each request consumes one token, so it naturally allows short bursts up to the bucket size while enforcing a long-term average rate. Fixed window counting simply counts requests per client within a discrete time slice, like a calendar minute, and resets to zero at the boundary, which is cheap to implement but allows a burst of up to double the limit right at the window edge, since a client could send the max at the end of one window and the max again at the start of the next. Sliding window approaches, whether a weighted average between adjacent fixed windows or a full log of timestamps, smooth out that edge-boundary burst problem at the cost of more memory or computation per check. Regardless of algorithm, well-designed APIs communicate limits via response headers like "X-RateLimit-Remaining" and "Retry-After," and return a 429 Too Many Requests status so clients can back off gracefully instead of guessing.
- Protects backend resources from being overwhelmed by any single client
- Token bucket allows legitimate short bursts while capping the sustained rate
- Sliding window avoids the double-burst problem at fixed window boundaries
- Standard headers (429, Retry-After) let clients implement proper backoff
AI Mentor Explanation
Token bucket rate limiting is like a bowler being allowed a maximum of six deliveries per over that refill only at the start of the next over, so a fast bowler can send down a tight burst but never exceed the overβs cap. Fixed window limiting is like counting deliveries strictly by the clock minute instead of by over, which lets a bowler sneak in extra deliveries right at the boundary between two minutes if the timing lines up. Sliding window limiting fixes that by tracking deliveries over any rolling minute, not just clock-aligned ones, so no clever timing trick lets more balls through than intended. Choosing between them is a tradeoff between simplicity and precisely fair enforcement.
Step-by-Step Explanation
Step 1
Identify the client
Rate limits are keyed by API key, user ID, or IP address to track usage per client.
Step 2
Choose an algorithm
Pick token bucket for burst tolerance, fixed window for simplicity, or sliding window for precise fairness.
Step 3
Check and update state
On each request, check remaining capacity; if allowed, decrement/consume and proceed, else reject.
Step 4
Respond with limit info
Return 429 with Retry-After and X-RateLimit-* headers when a client exceeds the limit.
What Interviewer Expects
- Ability to explain token bucket, fixed window, and sliding window tradeoffs
- Awareness of the fixed-window boundary burst problem specifically
- Knowledge of standard rate limit response headers and the 429 status
- Understanding of what key to rate limit on (API key, user, IP)
Common Mistakes
- Not knowing the fixed window boundary burst issue exists
- Rate limiting only by IP address, which breaks for shared NAT/corporate networks
- Returning a generic error instead of 429 with Retry-After
- Storing rate limit counters in a way that does not work across multiple server instances
Best Answer (HR Friendly)
βRate limiting caps how many requests a client can make in a given time period so no single user can overwhelm the system or use more than their fair share. I usually reach for a token bucket approach because it allows short bursts of activity while still enforcing a steady average rate, and I make sure the API clearly tells clients how many requests they have left and when they can try again.β
Code Example
function createTokenBucket(capacity, refillPerSecond) {
let tokens = capacity
let lastRefill = Date.now()
return function rateLimiter(req, res, next) {
const now = Date.now()
const elapsedSeconds = (now - lastRefill) / 1000
tokens = Math.min(capacity, tokens + elapsedSeconds * refillPerSecond)
lastRefill = now
if (tokens < 1) {
res.set('Retry-After', '1')
return res.status(429).json({ error: 'rate limit exceeded' })
}
tokens -= 1
res.set('X-RateLimit-Remaining', String(Math.floor(tokens)))
next()
}
}Follow-up Questions
- What is the fixed window boundary burst problem and how does sliding window fix it?
- How would you implement rate limiting across multiple server instances?
- What should a rate-limited client do when it receives a 429?
- How do you decide the right key to rate limit on: IP, user ID, or API key?
MCQ Practice
1. What advantage does token bucket rate limiting offer?
Token bucket refills steadily and permits bursts as long as tokens are available.
2. What is the main flaw of fixed window rate limiting?
Requests near the end of one window plus the start of the next can total nearly 2x the intended limit.
3. What HTTP status code should a rate-limited request return?
429 is the standard status for signaling that the client has exceeded its rate limit.
Flash Cards
Token bucket benefit? β Allows short bursts up to capacity while enforcing a steady long-term rate.
Fixed window flaw? β Allows up to double the limit right at the window boundary.
Sliding window benefit? β Avoids the fixed-window boundary burst problem at the cost of more state.
Correct status for exceeding a rate limit? β 429 Too Many Requests, often with a Retry-After header.