Stop 09 · API DesignTopics · 12/12

Rate Limiting Strategies

Part of the Backend Developer Roadmap

In short

One buggy script or one bored attacker can send thousands of requests a minute. A rate limiter decides how many each client gets, and politely answers 429 to the rest.

Different algorithms (fixed window, sliding window, token bucket) for capping request rates — each with different trade-offs between burstiness, fairness and implementation complexity.

The blob character hands out tokens from a bucket at a metro turnstile.

Think of it like this

Tokens at the metro gate

Picture a guard with a bucket of entry tokens. Each person takes one to pass. A tap drips a new token in every few seconds, and the bucket holds only ten. A rush can use all ten at once, then everyone waits for the drip. That's a token bucket.

Watch it happen

Token bucket: 5 tokens, refills 1 per second

T
0
T
1
T
2
T
3
T
4

1/5The bucket for this API key starts full with 5 tokens.

The big ideas

What you need to know

Fixed window

Count requests per clock minute. Simple, but a client can fire twice the limit across a minute boundary.

Sliding window

Count requests in the last 60 seconds from right now. Smoother and fairer, for a little more work.

Token bucket

Tokens refill at a steady rate and allow short bursts up to the bucket size. Very common for APIs.

Share the counter

With several servers, keep counts in Redis, so a client can't dodge limits by landing on another instance.

See it in code

Walk through the code

ts
1import rateLimit from "express-rate-limit";2import { RedisStore } from "rate-limit-redis";3 4const loginLimiter = rateLimit({5  windowMs: 15 * 60 * 1000,6  limit: 5,7  standardHeaders: "draft-7",8  legacyHeaders: false,9  store: new RedisStore({ sendCommand: (...args: string[]) => redis.sendCommand(args) }),10  message: { error: { code: "RATE_LIMITED", message: "Too many attempts, try later" } },11});12 13app.post("/auth/login", loginLimiter, loginHandler);

1/4Five login attempts per 15 minutes per IP. A fixed window is fine for login.

redis is a connected node-redis client and loginHandler is your route. Blocked requests get a 429 with your error body.

Save yourself the pain

Common mistakes

Oops

One global limit for every route.

Do this instead

Login, OTP and search need tight limits; cheap reads can be generous. Set limits per route and per user or key.

Oops

Keeping counters in each server's memory behind a load balancer.

Do this instead

Each instance counts separately, so the real limit multiplies. Use a shared store like Redis.

Your mission

Rate-limit a login route

~25 min

Quick check

Which algorithm allows a short burst but holds a client to a steady average rate?

Go deeper

  1. 1Implement a simple fixed-window rate limiter using Redis.
  2. 2Compare fixed window vs token bucket behavior around burst traffic.
  3. 3Learn why rate limiting needs shared storage (Redis) once you run multiple server instances.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge