How to Add Rate Limiting
Without rate limiting, attackers can hammer your API endpoints, exhaust your resources, run up your cloud bill, and brute-force authentication. This guide covers implementing rate limiting for different frameworks and architectures.
Find security issues automatically before attackers do.
Follow These Steps
Install a rate limiting library
Use a proven library rather than building your own rate limiter.
# Express.js
npm install express-rate-limit
# For distributed systems (multiple servers)
npm install @upstash/ratelimit @upstash/redisAdd basic rate limiting to all routes
Apply a general rate limit as a baseline for all API endpoints.
import rateLimit from 'express-rate-limit'
const generalLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per window
standardHeaders: true, // Return rate limit info in headers
legacyHeaders: false,
message: { error: 'Too many requests, please try again later' }
})
app.use(generalLimiter)Add stricter limits for sensitive endpoints
Authentication, password reset, and payment endpoints need much lower limits.
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // Only 5 login attempts per 15 minutes
message: { error: 'Too many login attempts, please try again later' }
})
app.use('/api/auth/login', authLimiter)
app.use('/api/auth/register', authLimiter)
app.use('/api/auth/reset-password', authLimiter)Implement distributed rate limiting
For serverless or multi-server environments, use a shared store like Redis.
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '10 s'),
analytics: true
})
// In your API route (Next.js)
export async function POST(req: Request) {
const ip = req.headers.get('x-forwarded-for') ?? '127.0.0.1'
const { success, remaining } = await ratelimit.limit(ip)
if (!success) {
return Response.json(
{ error: 'Rate limit exceeded' },
{ status: 429, headers: { 'X-RateLimit-Remaining': remaining.toString() } }
)
}
// Process request
}Add per-user rate limiting for authenticated endpoints
Rate limit by user ID instead of IP for authenticated users to prevent shared-IP issues.
const userLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 30,
keyGenerator: (req) => req.user?.id || req.ip,
message: { error: 'Rate limit exceeded' }
})
app.use('/api/', authenticate, userLimiter)Return proper rate limit headers
Include standard headers so clients can implement backoff.
// Standard rate limit headers (express-rate-limit does this automatically)
// X-RateLimit-Limit: 100
// X-RateLimit-Remaining: 95
// X-RateLimit-Reset: 1640000000
// Retry-After: 60 (on 429 responses)What You'll Achieve
Your API has general rate limiting on all routes, strict limits on authentication endpoints, distributed rate limiting for multi-server setups, and per-user limits for authenticated users.
Common Mistakes to Avoid
Mistake
Only rate limiting by IP address
Fix
Multiple users behind a NAT share the same IP. For authenticated routes, rate limit by user ID. Use IP-based limiting only for unauthenticated endpoints.
Mistake
Setting limits too high or too low
Fix
Monitor normal usage patterns before setting limits. Start generous and tighten. Auth endpoints should be 5-10 per 15 minutes. General API 100-500 per 15 minutes.
Mistake
Using in-memory rate limiting on serverless platforms
Fix
Serverless functions are stateless. Each invocation gets fresh memory. Use Redis or a distributed rate limiter like Upstash.
Frequently Asked Questions
What rate limits should I set?
General API: 100-500 requests per 15 minutes per IP. Auth endpoints: 5-10 per 15 minutes. Expensive operations (AI, email): 10-20 per hour. Adjust based on your specific usage patterns.
Does rate limiting work on serverless?
In-memory rate limiters do not work on serverless because each invocation is stateless. Use a distributed rate limiter backed by Redis (Upstash, Vercel KV, or similar).
Should I rate limit authenticated users?
Yes. Rate limit by user ID for authenticated users and by IP for unauthenticated requests. This prevents individual users from abusing your API.
Ready to Secure Your App?
VAS automatically scans your deployed app for the security issues covered in this guide. Get actionable results in minutes.
Start Security Scan