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.

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
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
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
Quick check
Which algorithm allows a short burst but holds a client to a steady average rate?
Go deeper
- 1Implement a simple fixed-window rate limiter using Redis.
- 2Compare fixed window vs token bucket behavior around burst traffic.
- 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.