· SWE Editorial · System Design  · 5 min read

Design a Rate Limiter: System Design Interview Guide

Rate limiter questions look simple and punish candidates who treat them that way. This guide covers the four algorithms interviewers expect you to know — token bucket, sliding window, fixed window counter — and how to build a distributed, Redis-backed version that survives a real follow-up.

Rate limiter questions look simple and punish candidates who treat them that way. This guide covers the four algorithms interviewers expect you to know — token bucket, sliding window, fixed window counter — and how to build a distributed, Redis-backed version that survives a real follow-up.

Why this question shows up in almost every loop

Rate limiters are one of the most commonly asked system design questions because they’re small enough to fully design in 45 minutes and deep enough to reveal how a candidate thinks about tradeoffs. The bar isn’t “can you block requests over N per second” — it’s whether you can articulate which algorithm fits which traffic pattern, and whether the thing works when it’s not running on a single machine.

This guide is the interview-prep version: what to say, in what order, and what follow-up questions to expect.

Step 1: clarify the requirements

Before touching an algorithm, nail down:

  • Scope of limiting: per-user, per-IP, per-API-key, or global?
  • Limit shape: “100 requests per minute” vs. “burst of 20 then steady 5/sec”?
  • Behavior on limit exceeded: hard reject (429) vs. queue vs. throttle?
  • Where does it run: API gateway, middleware in each service, or a dedicated sidecar?

Interviewers notice when candidates skip this and jump straight to “I’ll use a token bucket.” Ask first.

Step 2: the four core algorithms

Fixed window counter

Divide time into fixed windows (e.g., 00:00-00:59, 01:00-01:59) and count requests per window per key. Reset the counter at window boundaries.

  • Pro: trivial to implement, O(1) memory per key.
  • Con: burst-at-boundary problem — a client can send the full limit right before a window ends and the full limit again right after, doubling the effective rate in a short span.

Sliding window log

Store a timestamp for every request in a sorted set per key. On each new request, drop timestamps older than the window and count what’s left.

  • Pro: exact, no boundary problem.
  • Con: memory scales with request volume — a high-traffic key can store thousands of timestamps. Expensive at scale.

Sliding window counter (approximation)

Combine fixed windows with weighted interpolation: estimate the current rate as a weighted average of the previous window’s count and the current window’s count, weighted by how far into the current window you are.

  • Pro: near-exact accuracy with O(1) memory — the practical default for most production systems.
  • Con: slightly approximate; edge cases with highly irregular traffic can drift.

Token bucket

Each key has a bucket with capacity C, refilled at rate R tokens/sec. Each request consumes one token; if the bucket is empty, reject or delay.

  • Pro: naturally supports bursts up to bucket capacity while enforcing a long-run average rate — closest to how real traffic actually behaves.
  • Con: slightly more state to track (current token count + last refill timestamp) than a fixed counter.
AlgorithmMemory per keyBurst handlingAccuracyTypical use
Fixed windowO(1)Poor (boundary spikes)ApproximateSimple internal limits
Sliding window logO(N) requestsExactExactLow-volume, high-precision needs
Sliding window counterO(1)GoodNear-exactMost production APIs
Token bucketO(1)Best (allows controlled bursts)Exact for its modelPublic APIs, user-facing limits

For a system design interview, token bucket is the default answer unless the requirements specifically call for something else — say so, then explain why (burst tolerance without sacrificing long-run enforcement), then mention sliding window counter as the alternative if strict burst prevention matters more than burst tolerance.

Step 3: making it distributed

A rate limiter that only works on one server is a toy. The moment you have multiple API servers behind a load balancer, in-process counters are wrong — a user hitting server A and server B independently doubles their effective limit.

The standard fix: centralize state in Redis.

Client -> Load Balancer -> App Server 1 --\
                        -> App Server 2 ---> Redis (shared counters/buckets)
                        -> App Server N --/

Each app server, on a request, does an atomic read-modify-write against Redis (via INCR + EXPIRE for fixed window, or a Lua script for token bucket to make the check-and-decrement atomic). This is the natural bridge into the “distributed rate limiting” follow-up, which the companion article on distributed implementation covers in depth — Lua scripts, race conditions, and multi-region consistency.

Step 4: where does the limiter live

  • API Gateway / edge (e.g., Kong, Envoy, Cloudflare): centralizes the logic, protects all downstream services uniformly, but adds a network hop and a shared dependency.
  • Middleware in each service: more flexible per-endpoint limits, but duplicated logic and configuration across services.
  • Dedicated rate-limiting microservice: called synchronously by other services before processing a request — clean separation, but adds latency and a new single point of failure unless it’s made highly available.

Most real systems land on API gateway for coarse, global limits (per-IP, per-API-key) plus per-service middleware for fine-grained business-logic limits (e.g., “3 password reset emails per hour per account”).

Step 5: what interviewers probe next

Once the base design is on the board, expect:

  • “What happens if Redis goes down?” — good answers mention fail-open vs. fail-closed tradeoffs, and local in-memory fallback limiters as a degraded mode.
  • “How do you handle a user hitting two different regions?” — this is the multi-region consistency question; a reasonable answer accepts eventual consistency for rate limits (slight over-admission is usually an acceptable tradeoff vs. the cost of strict global consensus).
  • “How would you rate-limit by cost, not by request count?” (e.g., GraphQL queries of varying complexity) — token bucket generalizes naturally here: consume N tokens per request instead of 1, where N is a computed cost.

The interview-ready summary

If you only remember one structure for this question: clarify requirements → pick token bucket (or sliding window counter) with a one-sentence justification → centralize state in Redis for multi-server correctness → name the gateway-vs-middleware placement tradeoff → proactively raise the Redis-failure and multi-region questions before you’re asked. That sequence, delivered in under 15 minutes, reads as senior-level regardless of which specific algorithm you land on.

Further reading

The 0-to-1 SWE Interview Playbook (Amazon: https://www.amazon.com/dp/B0H256Z1MF?tag=sirjohnnymai-20) walks through this exact rate limiter framework alongside URL shorteners, chat systems, and news feed design — with the specific follow-up questions interviewers ask after each core answer, so you’re never caught flat-footed on the second question.

Back to Blog

Related Posts

View All Posts »

Design a Rate Limiter: Architecture and Algorithms

Token bucket vs. leaky bucket vs. sliding window log — the algorithm choice is only half the design. This piece is about where the limiter physically sits in your request path, and why that placement decision matters as much as the algorithm itself.