Rate Limiting
Rules
- Use token bucket for API endpoints, sliding window for auth/login routes
- Identify callers by API key first, fall back to IP — never IP-only for authenticated routes
- Return
429 Too Many Requests with Retry-After header (seconds) and X-RateLimit-Remaining header
- Store counters in Redis (or Upstash for serverless) — never in-memory for multi-instance deployments
- Set sensible defaults: 100 req/min for general API, 5 req/min for auth, 1000 req/min for reads
- Use
@upstash/ratelimit for serverless — it handles Redis atomicity and sliding window natively
- Implement rate limiting as middleware — apply globally, override per-route with stricter limits
- For Next.js: rate limit in middleware.ts or API route handlers, not in React components
- Separate limits by tier: free, pro, enterprise — store tier in JWT or database lookup
- Log rate limit hits with caller identity — detect abuse patterns early
Patterns
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,
});
const { success, limit, remaining, reset } = await ratelimit.limit(identifier);
Avoid
- In-memory rate limiting in serverless or multi-instance setups — state is lost between invocations
- Rate limiting only at the application layer — add CDN/edge limits too (Cloudflare, Vercel)
- Blocking legitimate users with overly aggressive limits — start permissive, tighten based on data
- Forgetting to rate limit webhooks and public form submissions