Learning centre

Protection

6 min readUpdated

What is rate limiting?

Quick answer

Rate limiting restricts how many requests a given client may make within a period of time, and rejects or delays anything beyond that. It is the simplest effective defence against brute-force login attempts, scraping, API abuse and small floods, because it makes each attempt cost the attacker time regardless of how the request is disguised. The hard parts are choosing what counts as a client and setting a limit that stops abuse without breaking legitimate bursts.

The common algorithms

Token bucket is the usual choice for public APIs because real clients are bursty — a page load may fire ten requests at once and then nothing for a minute. A strict per-second cap punishes that pattern; a bucket absorbs it while still limiting the sustained rate.

AlgorithmHow it behavesTrade-off
Fixed windowCounts requests per calendar interval, resets at the boundarySimple, but allows a double burst across the boundary
Sliding windowCounts over the trailing N secondsAccurate, more state to keep
Token bucketTokens refill at a steady rate; each request spends oneAllows short bursts while capping the sustained rate
Leaky bucketRequests queue and drain at a fixed rateSmooths traffic, but adds latency instead of rejecting

What to count per — the decision that matters most

A rate limit is only as good as its key. Limit per IP address and you punish everyone behind a shared connection: an office, a university, a mobile carrier's NAT, an entire country in some cases.

  • Per IP — the default; fine for anonymous traffic, unfair to shared connections
  • Per API key or account — much fairer, and possible wherever the client authenticates
  • Per session — works for logged-in users, and defeats attackers by making them log in
  • Per IP and endpoint — a tight limit on /login with a loose one everywhere else
  • Per subnet — for attacks spread across many addresses in one network

Responding well when a limit is hit

The correct status is `429 Too Many Requests`, and it should be accompanied by a `Retry-After` header telling the client how long to wait. Well-written clients honour it and back off; without it they retry immediately and make the problem worse.

For public APIs, it is worth returning the limit state on every response rather than only on rejection, so clients can pace themselves before hitting the wall.

A helpful rate-limit response
HTTP/1.1 429 Too Many Requests
Retry-After: 30
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 30

What rate limiting cannot do

A rate limit assumes an attacker is constrained by how fast one client can go. A distributed attack removes that assumption: ten thousand addresses each making two requests a second will pass any sane per-client limit while delivering twenty thousand requests a second to your origin.

This is why rate limiting is a layer rather than a solution. It handles brute force, scraping and single-source abuse very well. Distributed floods need mitigation that reasons about the traffic as a whole.

Frequently asked questions

Last updated