Step-by-Step Guide
6 steps

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

1

Install a rate limiting library

Use a proven library rather than building your own rate limiter.

Code Example
# Express.js
npm install express-rate-limit

# For distributed systems (multiple servers)
npm install @upstash/ratelimit @upstash/redis
2

Add basic rate limiting to all routes

Apply a general rate limit as a baseline for all API endpoints.

Code Example
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)
3

Add stricter limits for sensitive endpoints

Authentication, password reset, and payment endpoints need much lower limits.

Code Example
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)
4

Implement distributed rate limiting

For serverless or multi-server environments, use a shared store like Redis.

Code Example
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
}
5

Add per-user rate limiting for authenticated endpoints

Rate limit by user ID instead of IP for authenticated users to prevent shared-IP issues.

Code Example
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)
6

Return proper rate limit headers

Include standard headers so clients can implement backoff.

Code Example
// 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