Backend & Node.js · APIs, data and failure

How do you design rate limiting for an API?

Mediumrate limitingapiredisUpdated Oct 2026
Quiz this track

Short answer

Choose an algorithm such as fixed window, sliding window, token bucket or leaky bucket, key it by user, IP or API key, and enforce it atomically in a shared store. Return 429 with Retry-After and document the limits.

Rate limiting protects availability, enforces fair use and limits abuse. The algorithm determines burst behavior. Fixed windows are simple but allow a burst at the boundary. Token bucket allows controlled bursts up to the bucket size while enforcing an average rate.

js
function allow(bucket, now) {
  const elapsed = now - bucket.updatedAt;
  bucket.tokens = Math.min(
    bucket.capacity,
    bucket.tokens + elapsed * bucket.refillPerMs,
  );
  bucket.updatedAt = now;

  if (bucket.tokens < 1) return false;
  bucket.tokens -= 1;
  return true;
}
The token bucket refills over time and permits a burst up to capacity. In production this must be atomic.

Design decisions

  • Key by identity when possible, not only by IP, because NAT shares addresses
  • Use different limits for different endpoints and plans
  • Store counters in Redis with an atomic script or a single command
  • Return 429 with Retry-After and a clear error body
  • Consider a local in-process limiter plus a shared limiter to reduce Redis load
  • Exclude health checks and protect internal callers deliberately

The distributed version is the hard part. A read, compare and write in application code races across instances. Use a Lua script or a data structure that performs the increment and expiry atomically. Also decide whether limits are per second, per minute or a quota, and how the client discovers them.

Rate limiting is not the same as load shedding. Under extreme pressure, rejecting a percentage of traffic or prioritizing critical endpoints may be necessary even when every client is within its limit.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1What is the difference between a token bucket and a fixed window?
  2. 2How do you implement an atomic limiter across instances?
  3. 3Why is limiting by IP alone unreliable?
  4. 4What should a 429 response include?

Say it in the interview

I pick an algorithm based on burst behavior: fixed or sliding windows for simple quotas, token bucket when limited bursts are acceptable. I key by user or API key where possible and enforce the counter atomically in a shared store such as Redis. I return 429 with Retry-After and document the limits. The race across instances is the main implementation risk, so I never do a non-atomic read-modify-write.

Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.

Related questions

Reading is step one

Now say it out loud.

Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Backend & Node.js mock interview and get scored feedback on depth, clarity and confidence.