Decision guide

Rate-Limit Algorithms Compared

Which rate-limiting algorithm should you implement?

Side by side

CriterionFixed windowSliding window counterSliding logToken bucket / GCRALeaky bucket (queue)
AccuracyBoundary bursts (≤2×)High (approx.)ExactHighExact output rate
Burst behaviorEdge burstsSmoothSmoothBursts up to capacitySmoothed
State per key1 counter2 counters1 entry/request2 values (GCRA: 1)Queue
Retry-After calculationWindow endApproximateOldest entry expiryNaturalQueue position
ImplementationTrivialEasyEasy, memory-heavyLua script / libraryQueue + workers
Typical useInternal quotasGateways (Cloudflare-style)Security-sensitive actionsAPI plans (AWS, Stripe)NGINX limit_req, outbound calls

When to choose each

Fixed window

Count requests per calendar window (INCR + EXPIRE).

Choose when

  • Low-stakes limits
  • Simplest possible implementation

Avoid when

  • Login/OTP protection (boundary bursts)

Sliding window counter

Current window + weighted previous window.

Choose when

  • General-purpose API limits
  • Good accuracy at low cost

Avoid when

  • You need exact counts

Sliding log

Store each request timestamp in a sorted set.

Choose when

  • Small limits needing precision (e.g. 5 OTPs/hour)

Avoid when

  • High limits (memory per request)

Token bucket / GCRA

Refill tokens at a rate; allow bursts up to capacity (GCRA: one timestamp).

Choose when

  • Public APIs with bursty clients
  • Cost-weighted limits

Avoid when

  • Strict smoothing of outbound traffic

Leaky bucket (queue)

Queue requests and drain at a fixed rate.

Choose when

  • Shaping calls to a rate-limited third party

Avoid when

  • Low-latency APIs (adds queueing delay)

Verdict

Default to a token bucket (or GCRA) for API plans and a sliding window counter for simple per-key limits; use a sliding log only for small, security-sensitive limits, and a leaky bucket to shape your own outbound calls.

Learn more

Sources