Skip to content

Expert · Performance and reliability · topic 42 of 54 · 25 min

Rate limiting

Explanation

Rate limiting means allowing only a certain number of requests in a period, like 5 OTP requests per phone number per hour. It stops abuse, protects your servers and keeps things fair for everyone. Common methods are fixed window, sliding window and token bucket. When a client goes over the limit, answer 429 Too Many Requests with a Retry-After header.

Why limit requests

Without limits, one person or one bot can send thousands of requests a second. That can slow the app for everyone, cost you money, or help an attacker guess passwords.

  • Abuse: bots guessing passwords or OTPs on the login API.
  • Cost: every OTP SMS costs money, so SMS-bombing a number is expensive for you and annoying for the victim.
  • Fair use: one heavy user of a free API should not slow down everyone else.
  • Protection: a buggy client in a retry loop should not take your server down.
Think of it like this: Think of a ration shop rule: each card gets 5 kg of rice per month. It does not matter how many times you come to the shop; once your 5 kg is taken, you wait for next month. The card is the key you limit by, 5 kg is the limit, and a month is the window.

Three common methods

Fixed window: count requests in fixed blocks of time, like 100 per minute starting at 10:00:00, 10:01:00 and so on. It is simple and cheap. Its weakness: someone can send 100 at 10:00:59 and 100 more at 10:01:00, so 200 pass in two seconds.

Sliding window: look back over the last full period from now, for example "how many requests in the last 60 seconds?". This removes the burst at the window edge. It needs a little more memory or a smart estimate.

Token bucket: each user has a bucket that holds up to N tokens. Every request takes one token. Tokens drip back at a steady rate, like 1 per second. If the bucket is empty, the request is refused. This allows short bursts (a full bucket) but a steady average rate.

output
   +1 token every second
          |
          v
   |  o  o  o  |   bucket: up to 5 tokens
   |  o  o     |
   +-----------+
          |
          v
   each request takes 1 token
   empty bucket -> 429 Too Many Requests
A picture of the token bucket: tokens drip in, requests take them out.
MethodGood atWeak at
Fixed windowVery simple, one counter per keyBursts at the edge of two windows
Sliding windowSmooth and fair countingA bit more memory or maths
Token bucketAllows short bursts, steady averageTwo values to tune: size and refill rate

What to limit by

You need a key: who is this request from? For logged-in users, use the user id. For public APIs, use the API key. For login and OTP pages, use both the IP address and the phone number or email, because attackers change IPs. Different routes need different limits: login might be 5 per 15 minutes, while reading products might be 300 per minute.

Telling the client

output
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json

{"error":"Too many OTP requests. Try again in 30 seconds."}
A polite refusal: status 429 and how many seconds to wait.

Where to put it

  • API gateway or CDN (for example a cloud API gateway): stops floods before they reach your servers.
  • Nginx: has a built-in limit_req feature for simple per-IP limits.
  • Middleware in your app: knows the user id and the route, so it can do smart limits.
  • Redis: when you run many app servers, the counters must be shared, so they live in Redis.
javascript
async function allow(userId) {
  const windowId = Math.floor(Date.now() / 60000); // which minute is it?
  const key = 'rl:' + userId + ':' + windowId;
  const count = await redis.incr(key);              // add 1, get the new count
  if (count === 1) await redis.expire(key, 60);     // clean up after the minute
  return count <= 100;                              // 100 requests per minute
}
A fixed-window limit shared by all servers through Redis INCR and EXPIRE (runs on a server with Node.js and Redis).
Careful: A limit kept only in one server's memory does not work when you run several servers behind a load balancer: each server counts separately, so users get several times the limit. Use a shared store like Redis.

Watch the lesson

Rate limiting · 1/7

N requests per period

Rate limiting means allowing only a certain number of requests in a period.

Prefer a video by a teacher? Find free videos on “rate limiting algorithms token bucket fixed window explained” on YouTube ↗

In real life: Stopping OTP spam

A fintech app noticed one phone number receiving hundreds of OTP SMS an hour: someone was abusing the "Send OTP" button through a script. Each SMS cost money. The team added two limits: 3 OTPs per phone number per 10 minutes, and 20 OTP requests per IP address per hour, with counters in Redis. Extra requests get 429 with Retry-After, and the app shows "Please wait 9 minutes". SMS costs dropped the same day, and real users were not affected.

Practice (0/3 done)

Task 1 · Code · Javascript

Write createLimiter(limit, windowMs, now) that returns a function allow(key). allow returns true and counts the request if this key has made fewer than limit requests in the current fixed window, else false. The window number is Math.floor(now() / windowMs). Each key has its own count.

Task 2 · Code · Javascript

Build a TokenBucket class: constructor(capacity, refillPerSecond, now). The bucket starts full. take() first adds tokens for the time passed since the last call (seconds passed x refillPerSecond, never above capacity), then, if at least 1 token is there, removes 1 and returns true; otherwise returns false.

Task 3 · Practice

Design rate limits for a college admission portal: login, send OTP, submit application, and view course list. For each, give the key, the limit and the method.

Quick quiz

Question 1

1.Which status code means "you sent too many requests"?

Question 2

2.What is the weakness of a fixed window limit?

Question 3

3.In a token bucket, what happens when the bucket is empty?

Question 4

4.You run 4 app servers behind a load balancer. Where should rate-limit counters live?

Question 5

5.What does the Retry-After header tell the client?

Read more (free)

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

← Previous: Background jobs and queues