API Rate Limiting
Overview
If a hacker writes a Python script to hit your /login endpoint 5,000 times a second, they can easily brute-force user passwords, or simply overload your database and crash the server (a DDoS attack). Rate Limiting is a defensive middleware that monitors incoming IP addresses. If an IP exceeds a safe threshold (e.g., 100 requests per 15 minutes), the middleware intercepts the traffic and blocks them with a 429 Too Many Requests status code before they can damage the server.
Syntax
// npm install express-rate-limit
const rateLimit = require('express-rate-limit');
const express = require('express');
const app = express();
// 1. Create a Global Rate Limiter
const globalLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes timeframe
max: 100, // Limit each IP to 100 requests per windowMs
message: { error: "Too many requests from this IP, try again later." },
standardHeaders: true, // Returns rate limit info in the Headers!
});
// Apply it to ALL routes
app.use(globalLimiter);
// 2. Create a Strict Limiter specifically for Login/Password Reset endpoints!
const loginLimiter = rateLimit({
windowMs: 60 * 60 * 1000, // 1 hour timeframe
max: 5, // Block them if they fail 5 times! (Stops Brute Force)
message: { error: "Too many login attempts. Locked for 1 hour." }
});
// Apply it ONLY to the login route
app.post('/api/login', loginLimiter, (req, res) => { /* ... */ });Common Pitfalls
- Storing Rate Limit data in Server RAM on a distributed system. By default,
express-rate-limitstores IP tracking in Node's local memory. If you have 3 Node servers running behind a Load Balancer, the hacker can get 100 requests on Server 1, 100 on Server 2, etc. In production, you MUST configure the rate limiter to use a centralized Redis Cache store so all servers share the exact same IP counts. - Trusting
req.ipbehind a Proxy. If your Node app is hosted behind NGINX or Heroku, every single request will appear to come from the proxy's IP address, not the user's! The rate limiter will instantly block EVERY user on your site. You must enableapp.set('trust proxy', 1);so Express knows to read theX-Forwarded-Forheader instead.
Interview Questions
429 Too Many Requests status code, and what header is typically returned with it?A 429 status indicates the user has exhausted their API quota. It is industry standard to include a Retry-After header in the response, which informs the client exactly how many seconds they must wait before the server will accept traffic from them again.
Real-World Example
Fixing the Proxy IP bug when hosting Node.js on Render, Heroku, or behind Cloudflare.
const express = require('express');
const app = express();
// CRITICAL: Tells Express it is behind a load balancer.
// It will now safely extract the actual user's IP from the X-Forwarded-For header,
// allowing the Rate Limiter to function accurately!
app.set('trust proxy', 1);
app.use(rateLimiter);Check Your Knowledge
Test your understanding of API Rate Limiting with these quick questions.