Rate Limiter System Design (Token Bucket)

A rate limiter caps how many requests a client can make in a window. The three algorithms you need to know are token bucket, sliding window, and fixed window. Here's how each works, when to use it, and a token-bucket implementation.

Backend Engineerbackendrate-limitingsystem-design

What a rate limiter does

A rate limiter protects a service by rejecting requests from a client once they exceed an allowed rate (e.g. "100 requests per minute"). It's the answer to abuse, runaway scripts, and fair-use quotas - and a staple of system design interviews.

The three algorithms

Algorithm How it works Trade-off
Token bucket A bucket holds up to N tokens, refilled at a steady rate. Each request spends one token. Allows short bursts up to capacity. Feels nice to clients. The usual default.
Fixed window Count requests per fixed clock window (e.g. per minute). Simple, but allows a 2x burst at the window boundary.
Sliding window Track timestamps of recent requests (or a weighted count). Smooth + accurate, but more memory/compute.

Token bucket implementation

import time

CAPACITY = 10          # max burst
REFILL_PER_SEC = 10.0  # steady-state rate

_buckets = {}  # client_id -> (tokens, last_ts)

def allow(client_id: str) -> bool:
    now = time.monotonic()
    tokens, last = _buckets.get(client_id, (CAPACITY, now))
    tokens = min(CAPACITY, tokens + (now - last) * REFILL_PER_SEC)  # refill
    if tokens >= 1:
        _buckets[client_id] = (tokens - 1, now)
        return True
    _buckets[client_id] = (tokens, now)
    return False

The key idea: you don't run a timer to add tokens. You lazily refill on each request based on elapsed time - cheap and exact.

Designing it for real

Which to pick

Default to token bucket for API gateways - it absorbs bursts gracefully. Use sliding window when you need strict, smooth fairness and can afford the bookkeeping. Avoid plain fixed window when boundary bursts matter.

Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.

Try it in a workspace →

What you'll practice

FAQ

What is the best rate limiting algorithm?

Token bucket is the usual default - it allows short bursts up to a capacity while enforcing a steady average rate, which feels fair to clients. Use a sliding window when you need stricter, smoother fairness.

How do you rate limit across multiple servers?

Keep the counter/bucket in a shared store like Redis and update it atomically (e.g. a Lua script or INCR with a TTL), so every node enforces the same limit instead of each tracking its own.

What status code should a rate limiter return?

429 Too Many Requests, ideally with a Retry-After header telling the client how long to wait before retrying.

Keep learning

Return the Correct HTTP Status CodeBackend projectRepair Broken API PaginationBackend projectAdd CORS Middleware to an Express APIBackend projectBackend roadmapStep by step to hiredBackend interview questionsSTAR answersAll Backend projectsProjects hub

Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.

Open the workspace →