Nginx · The edge of your stack

How does rate limiting work in Nginx?

Mediumrate limitinglimit_req429Updated Oct 2026
Quiz this track

Short answer

limit_req_zone defines a shared counter keyed by client or API key and a rate. limit_req applies it per location, with burst allowing short spikes and nodelay deciding whether excess requests wait.

The algorithm is a leaky bucket. Requests drain at the configured rate, and burst defines how many can queue. Without nodelay, queued requests are delayed; with nodelay, excess requests over the burst are rejected immediately.

nginx
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

server {
    location /api/ {
        limit_req zone=api burst=20 nodelay;
        limit_req_status 429;
        limit_req_log_level warn;
        proxy_pass http://backend;
    }
}
Each client IP gets its own bucket; the zone is shared across workers.

Tuning and pitfalls

  • Key on $binary_remote_addr to save memory, or on an API key when that better represents a client
  • rate accepts values such as 10r/s or 60r/m
  • burst absorbs legitimate spikes; too small a burst rejects normal traffic
  • nodelay rejects excess requests instead of adding latency
  • Behind a load balancer, configure real_ip first or every request appears to come from the proxy
Rate limiting per Nginx instance is not global. With several edge nodes, each node has its own counter, so use a shared gateway or accept approximate limits.

Follow-ups you should expect

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

  1. 1What does burst control?
  2. 2What is the difference between rate limiting with and without nodelay?
  3. 3Why does every client look identical behind a proxy?
  4. 4How would you apply a stricter limit to login attempts?

Say it in the interview

I define a limit_req_zone keyed by client address with a rate, then apply it in the location. Burst allows short spikes, and nodelay rejects excess traffic immediately rather than delaying it. I set limit_req_status to 429 and return a clear error. Behind a load balancer I configure real_ip first, and I remember that the counter is per Nginx instance, not global.

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 Nginx mock interview and get scored feedback on depth, clarity and confidence.