Skip to content
Why Rate Limit?
step 1/5

Reading — step 1 of 5

Read

~3 min readWhy Rate Limit?

Why Rate Limit?

A rate limiter answers one question, on every request, in microseconds: has this client already had its fair share? If yes, the request is refused before it costs you anything — no database query, no worker thread, no invoice. Every serious API has one, because without it four things reliably happen:

  • The buggy client. Someone ships a retry loop with no delay. A single laptop retrying every 10 ms is 100 requests per second of pure waste — forever, until you block it.
  • The attacker. Credential stuffing against /login, scraping against /search, or a plain flood. If handling a request costs you more than sending it costs them, you lose by arithmetic.
  • The noisy neighbor. One tenant's batch job saturates the database and every other tenant's latency spikes. Fairness does not happen on its own; it is enforced.
  • The surprise bill. At $0.001 per serverless invocation, a runaway script is a heart-attack invoice by morning.

The anatomy of a limit

Every limit is three design decisions:

  1. Identity — who is "the client"? Per-IP (1,000/hour), per-user (100/min), per-API-key (10,000/day, tiered free/pro/enterprise), per-endpoint (/login = 5/min as brute-force defense), or global (50,000/s protecting total capacity). Production systems stack several of these — that is this course's Tiered Limits lesson.
  2. Budget — how much, per how long? 100 per minute — but may the client spend all 100 in one second? Whether bursts are tolerated is exactly where the algorithms in the next four lessons differ.
  3. Verdict — what happens on excess? Drop (answer 429 and do no work — the default for APIs), queue (hold the request and serve it late — used in traffic shaping, rarely for interactive HTTP), or throttle (serve, but slowly).

The HTTP contract

HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1716383472

Status 429 Too Many Requests is defined in RFC 6585. Retry-After tells a well-behaved client exactly how long to back off. The X-RateLimit-* trio is a de facto convention — GitHub and Stripe both ship variants, and an IETF draft is standardizing RateLimit headers — that lets clients pace themselves before hitting the wall: watch Remaining approach zero and slow down.

Two traps before you write any code

Retry storms. Clients that treat 429 as a transient error and retry instantly convert a small overload into a synchronized flood — the limiter causes the very traffic it is refusing. The cure lives on both sides: the server always sends Retry-After; the client honors it, with exponential backoff plus jitter so a thousand blocked clients don't all come back in the same millisecond.

Identity is slippery. Per-IP looks easy, but a university NAT or a mobile carrier puts thousands of people behind one address, and X-Forwarded-For is attacker-controlled unless your own proxy overwrites it. Prefer authenticated identity (API key, user id) wherever it exists; keep per-IP limits for the unauthenticated edge.

Your exercise

Draft the limit table for a small API with /login, /search, and /export: choose identity, budget, and verdict for each. Then attack your own numbers the way a reviewer would. At 5/min per IP, /login yields at most 5 × 60 × 24 = 7,200 password guesses per day from one address — down from millions. If /export allows 1,000/min per user, one user can pull your entire dataset every hour; that number fails review. Every limit you keep should survive this back-of-envelope test — the next seven lessons are about enforcing numbers, not choosing them.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…