Stop 16 · Security Across the StackTopics · 4/7

Rate Limiting

Part of the Full Stack Developer Roadmap

In short

Without a limit, one script can try 10,000 passwords a minute or hammer your API until it falls over. Rate limiting says: slow down, come back later.

Capping request rates on your backend to blunt brute-force login attempts and abuse — especially important on auth endpoints your frontend's login form hits.

The blob serving rotis in a hostel mess holds up a hand next to a sand timer.

Think of it like this

The hostel mess roti rule

The mess bhaiya hands out rotis fast, but each student gets a few per round. Come back too soon and he points at the sand timer. Nobody goes hungry, and one hungry senior can't empty the whole tray. That's a rate limit.

Watch it happen

Login attempts from one IP, limit 5 per 15 minutes

#1
0
#2
1
#3
2
#4
3
#5
4
#6
5
#7
6

1/5Each cell is a POST /login from the same IP inside one 15 minute window.

The big ideas

What you need to know

429 Too Many Requests

The standard reply when a client goes over the limit, often with a Retry-After header in seconds.

Pick the right key

Limit by IP for public routes, by user id or API key once logged in. Login routes deserve the strictest limits.

Share counters across servers

With three app servers, in-memory counters give each user three times the limit. Store counts in Redis instead.

Windows and buckets

Fixed windows are simple. Sliding windows and token buckets smooth out bursts at the edge of a window.

See it in code

Walk through the code

ts
1import { rateLimit } from "express-rate-limit";2 3const loginLimiter = rateLimit({4  windowMs: 15 * 60 * 1000, // 15 minutes5  limit: 5,                 // 5 tries per IP per window6  standardHeaders: "draft-7",7  legacyHeaders: false,8});9 10app.post("/login", loginLimiter, loginHandler);

1/3Five requests per IP every 15 minutes. Counters live in memory unless you plug in a store like Redis.

Behind a proxy like Nginx or a cloud load balancer, set app.set("trust proxy", 1) so the limiter sees the real client IP, not the proxy's.

Save yourself the pain

Common mistakes

Oops

Keeping counters in memory with several server instances.

Do this instead

Use a shared store like Redis so every instance sees the same count.

Oops

Forgetting trust proxy, so every user shares the load balancer's IP.

Do this instead

Set trust proxy correctly, or one busy user locks out everyone.

Your mission

Lock yourself out

~15 min

Quick check

You run 4 instances of your API, each with an in-memory limit of 100 requests per minute. Roughly how many can one client get through?

Go deeper

  1. 1Add stricter rate limits specifically on login and signup endpoints.
  2. 2Show a clear, friendly message on the frontend when a user is rate-limited.
  3. 3Learn rate limiting needs shared storage (Redis) once you run multiple backend 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