Skip to main content

a6-plugin-limit-req

Overview

The limit-req plugin rate-limits requests using the leaky bucket algorithm. Unlike limit-count (fixed window), it provides smooth traffic shaping by throttling burst requests with configurable delays. This prevents traffic spikes from overwhelming upstream services.

When to Use

  • Smooth traffic to protect upstream from sudden spikes
  • Enforce per-second QPS limits
  • Throttle (delay) excess requests instead of rejecting them immediately
  • Combine with limit-count for both per-second and per-hour limits

Plugin Configuration Reference

Core Fields

FieldTypeRequiredDefaultDescription
ratenumberYesSustained requests per second (QPS). > 0
burstnumberYesExtra burst capacity above rate. >= 0
keystringYesVariable to count requests by
key_typestringNo"var"Key type: "var" or "var_combination"
rejected_codeintegerNo503HTTP status on rejection (200–599)
rejected_msgstringNoCustom rejection message body
nodelaybooleanNofalseIf true, don't delay burst requests
allow_degradationbooleanNofalseAllow requests when plugin fails
policystringNo"local"Storage: "local", "redis", or "redis-cluster"

Redis Fields (when policy: "redis")

FieldTypeRequiredDefault
redis_hoststringYes
redis_portintegerNo6379
redis_usernamestringNo
redis_passwordstringNo
redis_databaseintegerNo0
redis_timeoutintegerNo1000
redis_sslbooleanNofalse

Redis Cluster Fields (when policy: "redis-cluster")

FieldTypeRequiredDefault
redis_cluster_nodesarray[string]Yes
redis_cluster_namestringYes
redis_passwordstringNo
redis_timeoutintegerNo1000
redis_cluster_sslbooleanNofalse

Leaky Bucket Algorithm

Incoming requests → [   Bucket (burst capacity)   ] → Leak at 'rate' per second → Upstream
↓ overflow (> rate + burst)
Rejected (503/429)
Request RateBehavior
rateProcessed immediately
> rate but ≤ rate + burstDelayed (smoothed) if nodelay: false; immediate if nodelay: true
> rate + burstRejected with rejected_code

nodelay Explained

  • nodelay: false (default): Burst requests are delayed (APISIX sleeps) to smooth traffic. Higher latency for burst requests but protects upstream.
  • nodelay: true: Burst requests are processed immediately without delay. Better latency but upstream sees spikes up to rate + burst.

Step-by-Step: Basic Rate Limiting

1. Strict QPS limit (no burst)

a6 route create -f - <<'EOF'
{
"id": "strict-qps",
"uri": "/api/*",
"plugins": {
"limit-req": {
"rate": 10,
"burst": 0,
"key": "remote_addr",
"rejected_code": 429,
"nodelay": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF

10 requests per second per IP. Anything above is immediately rejected.

2. Smooth traffic with burst allowance

a6 route create -f - <<'EOF'
{
"id": "smooth-api",
"uri": "/api/*",
"plugins": {
"limit-req": {
"rate": 5,
"burst": 10,
"key": "remote_addr",
"rejected_code": 429
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF
  • 5 req/s sustained rate
  • Up to 10 extra burst requests (delayed to smooth traffic)
  • Requests above 15/s rejected with 429

Common Patterns

Multi-variable key

{
"plugins": {
"limit-req": {
"rate": 10,
"burst": 5,
"key_type": "var_combination",
"key": "$remote_addr $http_x_api_version",
"rejected_code": 429
}
}
}

Separate buckets per (IP + API version header) combination.

Combine limit-req + limit-count

{
"plugins": {
"limit-req": {
"rate": 10,
"burst": 20,
"key": "remote_addr",
"rejected_code": 429
},
"limit-count": {
"count": 1000,
"time_window": 3600,
"key": "remote_addr",
"rejected_code": 429
}
}
}
  • limit-req: Smooths per-second traffic (10 QPS with burst)
  • limit-count: Enforces hourly quota (1000/hour)

This prevents both short-term spikes and long-term abuse.

Distributed rate limiting with Redis

{
"plugins": {
"limit-req": {
"rate": 100,
"burst": 50,
"key": "remote_addr",
"policy": "redis",
"redis_host": "redis.example.com",
"redis_port": 6379,
"redis_password": "secret",
"rejected_code": 429
}
}
}

limit-req vs limit-count

Aspectlimit-reqlimit-count
AlgorithmLeaky bucketFixed window
UnitRequests per secondRequests per time window
Burst handlingDelays or allowsHard reject
Traffic shapingSmoothBursty at window boundaries
Response headersNoneX-RateLimit-*
Group supportNoYes
Best forQPS protection, traffic smoothingQuota enforcement, API plans

Troubleshooting

SymptomCauseFix
High latency on burstnodelay: false delays requestsSet nodelay: true for lower latency
All burst requests rejectedburst: 0Increase burst to allow some excess
No rate limit headerslimit-req doesn't add headersUse limit-count if headers needed
Limits not shared across nodespolicy: "local"Switch to "redis" or "redis-cluster"
Key empty, single bucket for allVariable doesn't existVerify key variable name

Config Sync Example

version: "1"
routes:
- id: smooth-api
uri: /api/*
plugins:
limit-req:
rate: 10
burst: 20
key: remote_addr
rejected_code: 429
upstream_id: api-upstream
upstreams:
- id: api-upstream
type: roundrobin
nodes:
"backend:8080": 1

This page is generated from a6-plugin-limit-req/SKILL.md in the api7/a6 repository. Browse all skills on the AI Agent Skills page.

API7.ai Logo

The digital world is connected by APIs,
API7.ai exists to make APIs more efficient, reliable, and secure.

Sign up for API7 newsletter

Product

API7 Gateway

SOC2 Type IIISO 27001HIPAAGDPRRed Herring

Copyright © APISEVEN PTE. LTD 2019 – 2026. Apache, Apache APISIX, APISIX, and associated open source project names are trademarks of the Apache Software Foundation