Slow Down Abuse — Protect Real Users
Rate Limiting
Cap how many requests a client can make. The `express-rate-limit` package is the standard.
What you'll learn
- Apply a basic rate limit
- Per-route and per-IP limits
- Use Redis as the store across instances
Rate limiting is your cheapest defense against abuse — bots, scrapers, brute-force attacks. Apply it before they reach expensive operations (DB, password hashing, AI calls).
Basic Setup
npm install express-rate-limit import rateLimit from "express-rate-limit";
const limiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 100, // 100 requests/min per IP
standardHeaders: true, // adds RateLimit-* headers
legacyHeaders: false,
});
app.use(limiter); Clients hit the limit → 429 Too Many Requests automatically.
Per-Route Limits
Stricter limits on expensive endpoints:
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 min
max: 5,
message: "Too many login attempts",
});
app.post("/api/auth/login", authLimiter, loginHandler); 5 attempts per 15 minutes. Makes brute-force impractical.
Custom Key
By default it limits per IP. For per-user:
rateLimit({
windowMs: 60_000,
max: 100,
keyGenerator: (req) => req.user?.id ?? req.ip,
}); Distributed Limits
With multiple Node instances, the in-memory counter resets per process — useless. Use Redis:
npm install rate-limit-redis ioredis import { RedisStore } from "rate-limit-redis";
import { Redis } from "ioredis";
const redis = new Redis(process.env.REDIS_URL);
const limiter = rateLimit({
store: new RedisStore({
sendCommand: (...args) => redis.call(...args),
}),
windowMs: 60_000,
max: 100,
}); Now all instances share the same counter.
Beyond Rate Limiting
For sophisticated abuse: Cloudflare, AWS WAF, Fastly. These see patterns across IPs and block before traffic reaches you. Node rate-limit is the baseline.
End of Chapter
That wraps Express. Next chapter: persisting data — databases, caches, queues.
Databases →