Rate Limiting & Abuse Prevention
Prevent abuse, contain bursts, and enforce fair use across authenticated APIs, public endpoints, and expensive operations.
Options
Rate Limit Algorithm*
What to Limit By*
Abuse Prevention Layer
Response Behavior*
Decision Points
Do you have unauthenticated endpoints (signup, login, public API)?
If yes
Add per-IP limits on those endpoints plus CAPTCHA on threshold. Assume credential-stuffing is attempted on day one.
If no
Per-user limits on authenticated APIs are sufficient.
Do different customer tiers pay for different rate limits?
If yes
Keyed-on-API-key limits with plan-configured thresholds; expose a usage endpoint.
If no
A single default limit keeps configuration simple.
Do you expect adversarial traffic (credential stuffing, scraping, spam)?
If yes
Use sliding window or token bucket — fixed window leaks under boundary timing attacks. Pair with WAF and bot detection.
If no
Fixed-window with Redis INCR + EXPIRE is cheap, simple, and sufficient.
Do you have legitimate burst patterns (batch imports, bulk API calls)?
If yes
Token bucket is the right model — allows bursts while enforcing a sustained rate. The standard for commercial API gateways.
If no
Sliding window is simpler and has lower memory overhead.
Do you run multiple server nodes behind a load balancer?
If yes
Use centralized Redis for rate-limit state (Upstash Ratelimit, redis-cell). Per-node local counters let attackers get N×limit by rotating through nodes.
If no
In-process counters are fine for single-node deployments and dramatically cheaper.
Should users get a warning before they hit a hard limit?
If yes
Emit soft-limit warnings via response headers (X-RateLimit-Remaining) and optionally an in-app notification when usage >80%. Prevents angry support tickets.
If no
Silent throttling at the hard limit is simpler but worse UX — only acceptable for internal APIs.
Do you have enterprise customers who negotiate custom limits?
If yes
Build an admin override table keyed on tenant/API-key. Do not hardcode limits — operations team will need to raise them without deploys.
If no
Static per-tier limits in config are simpler and easier to reason about.
Can a single user enqueue unbounded background jobs (imports, scrapes, AI calls)?
If yes
Rate-limit the enqueue side separately from the API side. Prevents queue-flooding attacks that bypass request-layer limits.
If no
API-layer limits are sufficient; background jobs are produced by your own code only.
Do you have legitimate short bursts you want to allow (e.g. pagination fan-out)?
If yes
Use token bucket with a burst allowance (bucket size > refill rate). Clients can consume the bucket quickly, then settle.
If no
A flat rate is simpler — bursts are a policy decision, not a default.
Are you exposed to L3/L4 DDoS (public API, unauthenticated endpoints)?
If yes
Put Cloudflare, AWS Shield, or Fastly in front of your origin. Application-layer rate limiting cannot absorb network-layer floods.
If no
Application-layer limits are sufficient for authenticated-only APIs.
Do some endpoints cost 100x more than others (AI calls, complex queries, exports)?
If yes
Rate-limit by computational cost (credits/tokens per request) not by request count. Pricing and abuse protection align naturally.
If no
Request-count limits are simpler and sufficient when endpoint costs are roughly uniform.
Do specific features (uploads, AI generations) have their own cost or quota model?
If yes
Add per-feature limits in addition to global ones. A user at their upload quota should still be able to read the API.
If no
Per-route limits are enough and keep configuration centralized.
Is this a public developer API with SDKs / third-party integrations?
If yes
Always return X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After headers. Well-behaved clients need them to back off correctly.
If no
Minimum viable is Retry-After on 429 responses — detailed headers are nice-to-have for internal APIs.
Do you have health checks, metrics endpoints, or internal traffic hitting rate-limited routes?
If yes
Exempt health checks and internal service-to-service calls by IP allowlist or dedicated service tokens. Otherwise monitoring will trip your own limits.
If no
Default behavior — all traffic counts — is simpler and auditable.
Do you have authentication endpoints at risk of credential stuffing?
If yes
Rate-limit failed logins separately (per-account + per-IP), with exponential backoff and lockout after N attempts. Combine with CAPTCHA on threshold.
If no
General per-IP limits are insufficient for auth — always treat login and password reset as a separate budget.
Tradeoffs
False positives behind corporate NATs; attackers bypass with rotating proxies
Noisy-neighbor protection — one tenant cannot starve others
Allows bursts but requires a per-identity bucket state in Redis — higher memory footprint
Meaningful latency cost at the edge if the WAF is geographically distant from users
Implementation Examples
Edge-based rate limiting with sophisticated dimensions and bot-score integration.
Serverless-friendly rate limiter using Redis with sliding-window and token-bucket algorithms.
API-gateway-level rate limiting with global consistency via an external service.