TL;DR — Kong Gateway offers far more than basic rate limiting. By combining sliding window algorithms, distributed counters via Redis, and granular per-consumer policies, you can enforce sophisticated traffic controls. Paired with request transformation capabilities—header manipulation, body rewriting, and upstream URI remapping—you can decouple your external API contract from internal microservice topology.
Introduction
API gateways have become the de facto control plane for modern microservice architectures. Kong Gateway, built on the battle-tested NGINX proxy core, provides a plugin-driven architecture that lets you enforce policies at the edge without touching your upstream services. While many teams use Kong for simple route matching and basic authentication, the real power emerges when you combine its rate limiting and request transformation plugins into cohesive, production-grade traffic policies.
This article goes beyond the documentation basics. We’ll explore advanced configurations that solve real problems: preventing noisy neighbors from starving critical endpoints, transforming legacy API contracts on the fly, and building multi-layered rate limiting strategies that scale horizontally.
Architecture Overview
Before diving into specific patterns, it helps to understand how Kong’s plugin execution order shapes both rate limiting and transformation behavior. Kong processes plugins in a defined sequence: pre-function, authentication, rate-limiting, request-transformer, proxy, response-transformer, and post-function.
This ordering matters enormously. A rate limiting check that fires after a request transformer has already modified the upstream URI could produce unexpected quota consumption. Conversely, running transformation before rate limiting means your quota is consumed based on the transformed request, which is usually what you want.
Client → Kong Edge → [pre-function] → [auth] → [rate-limit] → [transformer] → [upstream service]
In a typical production deployment on Kubernetes using Kong Gateway with the Kong Ingress Controller, you declare these policies as KongPlugin and KongClusterPlugin CRDs, attaching them to routes or consumers via KongPluginConfiguration.
Advanced Rate Limiting Patterns
Sliding Window vs. Fixed Window
Kong’s rate-limiting plugin supports both fixed-window and sliding-window algorithms. The fixed window is simpler and faster but suffers from the boundary burst problem: a client can exhaust their quota at 11:59:59 and immediately start consuming again at 12:00:00, effectively doubling their allowed throughput at the boundary.
The sliding window algorithm solves this by tracking request timestamps across window boundaries. Kong delegates the sliding window computation to a Redis backend when configured for distributed mode.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: sliding-rate-limit
plugin: rate-limiting
config:
minute: 60
hour: 1000
policy: redis
redis_host: redis-headless.default.svc.cluster.local
redis_port: 6379
sliding_window: true
fault_tolerant: true
Setting fault_tolerant: true is critical in production. If Redis becomes unavailable, Kong continues to proxy requests rather than failing the entire pipeline. This trade-off between accuracy and availability is a deliberate architectural choice worth understanding.
Multi-Layered Rate Limiting
A single rate limit rarely suffices in production. Consider an e-commerce platform where you need:
- Global limits to protect infrastructure (10,000 requests/minute across all consumers)
- Per-consumer limits to prevent individual abuse (100 requests/minute per API key)
- Per-route limits to protect expensive endpoints like checkout (10 requests/minute)
Kong supports stacking multiple rate-limiting plugin instances. Each instance creates independent counters, and all must pass for the request to proceed.
# Global infrastructure protection
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: global-rate-limit
plugin: rate-limiting
config:
minute: 10000
policy: redis
redis_host: redis-headless.default.svc.cluster.local
redis_port: 6379
limit_by: ip
# Per-consumer protection
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: consumer-rate-limit
plugin: rate-limiting
config:
minute: 100
hour: 5000
policy: redis
redis_host: redis-headless.default.svc.cluster.local
redis_port: 6379
limit_by: consumer
# Expensive endpoint protection
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: route-rate-limit
plugin: rate-limiting
config:
minute: 10
policy: redis
redis_host: redis-headless.default.svc.cluster.local
redis_port: 6379
limit_by: ip
Attach each plugin to the appropriate route or consumer group. Kong evaluates them in the order they are registered, returning a 429 Too Many Requests as soon as any limit is breached.
Distributed Rate Limiting with Redis Cluster
When running Kong in a multi-node deployment, local in-memory counters become useless—each node maintains its own state, allowing clients to distribute requests across nodes and bypass limits entirely. Redis (or Redis Cluster) solves this by centralizing counter state.
For high-throughput scenarios, configure Kong to use Redis Cluster with sentinel-aware failover:
config:
policy: redis
redis_host: redis-cluster.example.com
redis_port: 6379
redis_password: "${REDIS_PASSWORD}"
redis_timeout: 2000
redis_ssl: true
redis_ssl_verify: false
Monitor Redis latency closely. The rate-limiting plugin adds a round-trip to Redis for every request. At 10,000 requests per second, even 1ms of Redis latency translates to 10 seconds of cumulative blocking per second across the gateway cluster. Connection pooling and pipelining become essential.
Per-Consumer and Per-Route Granularity
Kong allows you to apply rate limits at the consumer level, which is invaluable for tiered API plans. A free-tier user gets 100 requests/hour, while a premium user gets 10,000 requests/hour. By associating rate-limiting plugins with specific consumer objects, Kong automatically applies the correct limit based on the authenticated identity.
# Premium consumer with higher limits
apiVersion: konghq.com/v1
kind: KongConsumer
metadata:
username: premium-user-42
custom_id: user-42
---
# Apply premium rate limit to this consumer
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: premium-rate-limit
plugin: rate-limiting
config:
minute: 500
hour: 10000
policy: redis
redis_host: redis-headless.default.svc.cluster.local
redis_port: 6379
limit_by: consumer
Request Transformation Patterns
Header Manipulation at Scale
The request-transformer plugin is one of Kong’s most versatile tools. It allows you to add, remove, rename, and replace headers before requests reach upstream services. This is particularly useful when migrating from a monolithic API to microservices, where internal services expect headers that external clients never send.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: header-transformation
plugin: request-transformer
config:
add:
headers:
- "X-Request-Source:kong-gateway"
- "X-Internal-Version:2"
remove:
headers:
- "X-Powered-By"
- "Server"
replace:
headers:
- "X-Forwarded-Proto:${scheme}"
A common production pattern is injecting correlation IDs. If your upstream services rely on X-Correlation-ID for distributed tracing but your clients don’t send it, Kong can generate and inject one automatically:
add:
headers:
- "X-Correlation-ID:${uuid}"
Body Transformation and Payload Rewriting
The request-transformer plugin also supports body manipulation, though with caveats. Kong can add, remove, and replace JSON fields in the request body. This is useful for protocol translation—for example, converting a legacy field name to a new schema that an upgraded microservice expects.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: body-transformation
plugin: request-transformer
config:
replace:
body:
- "old_field_name:new_field_name"
add:
body:
- "source_platform:kong"
- "api_version:v3"
Be cautious with large payloads. Kong buffers the entire request body into memory during transformation. For payloads exceeding a few megabytes, consider offloading transformation to a dedicated service using Kong’s serverless_pre_function plugin with a Lua script that streams the body.
Upstream URI Remapping
One of the most powerful transformation patterns is remapping the upstream URI. This lets you present a clean, versioned external API while routing to differently structured internal services.
apiVersion: configuration.konghq.com/v1
kind: KongRoute
metadata:
name: v2-product-route
annotations:
konghq.com/strip-path: "true"
spec:
paths:
- /api/v2/products
backends:
- name: product-service
port:
number: 8080
path: /internal/catalog/items
The strip-path annotation removes /api/v2/products from the URL before forwarding to the upstream, so the service receives /internal/catalog/items. Combined with header transformations, this allows you to completely decouple external and internal API contracts.
Combining Transformation with Rate Limiting
The most realistic production patterns combine both capabilities. Consider an API versioning strategy where /api/v1/* routes have generous rate limits (legacy clients) and /api/v2/* routes have stricter limits (new features, protected resources). Request transformation ensures v1 requests are properly routed and modified before hitting the v1 rate limit policy.
# v1 route with legacy rate limits
apiVersion: configuration.konghq.com/v1
kind: KongRoute
metadata:
name: v1-route
spec:
paths:
- /api/v1
plugins:
- name: rate-limiting
config:
minute: 200
policy: redis
redis_host: redis-headless.default.svc.cluster.local
- name: request-transformer
config:
add:
headers:
- "X-Api-Version:1"
remove:
headers:
- "X-Experimental-Feature"
Patterns in Production
Caching Rate Limit Headers in Responses
Clients often need to know their remaining quota without making an additional call. Kong’s rate-limiting plugin automatically injects X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers into responses. However, when multiple rate-limiting plugins are stacked, these headers can conflict.
A production pattern is to use the response-transformer plugin to consolidate these headers into a single, well-structured response header:
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: consolidate-rate-headers
plugin: response-transformer
config:
add:
headers:
- "X-RateLimit-Info:${kong.client.get_rate_limit_remaining()} remaining of ${kong.client.get_rate_limit_limit()}"
Circuit Breaking as a Complement to Rate Limiting
Rate limiting protects your API from being overwhelmed by too many requests. Circuit breaking protects it from being overwhelmed by slow upstream responses. Kong doesn’t include a native circuit breaker plugin, but the upstream entity supports connect_timeout, write_timeout, and read_timeout settings that serve a similar purpose by failing fast when upstreams are unresponsive.
Combine short timeouts with aggressive rate limiting to create a defensive perimeter:
apiVersion: configuration.konghq.com/v1
kind: KongUpstream
metadata:
name: payment-service
spec:
timeout:
connect: 1000
write: 2000
read: 3000
retries: 2
retries_status:
- 502
- 503
- 504
Monitoring and Observability
Rate limiting and transformation policies are only as good as your ability to observe them. Kong exposes Prometheus metrics through the prometheus plugin, including kong_limit_requests_total and kong_limit_rejected_requests_total.
Set up alerts on kong_limit_rejected_requests_total exceeding a threshold. A sudden spike indicates either a misconfigured limit or a potential abuse pattern. Pair this with distributed tracing (via the zipkin or skywalking plugins) to correlate rate-limited requests with specific consumer behavior.
Key Takeaways
- Use sliding window algorithms with Redis for accurate rate limiting in distributed deployments; fixed windows create boundary bursts that undermine your quotas.
- Stack multiple rate-limiting plugins to enforce global, per-consumer, and per-route limits simultaneously—each creates an independent counter.
- Always set
fault_tolerant: trueon Redis-backed rate limiting to prevent gateway outages when Redis is unavailable. - Leverage request transformation to decouple external API contracts from internal microservice topology, using header injection, body rewriting, and upstream URI remapping.
- Combine rate limiting with circuit breaking through aggressive timeout configuration to create a multi-layered defensive perimeter around your upstream services.
- Monitor rejection metrics via Prometheus and set alerts; a spike in rejected requests is an early signal of misconfiguration or abuse.
Further Reading
- Kong Gateway Rate Limiting Documentation — The official reference covering all configuration options, algorithms, and backend policies.
- Kong Gateway Request Transformer Plugin — Complete guide to header, body, and URI transformation capabilities.
- Kong Gateway Production Best Practices — Official production deployment guide covering Redis clustering, high availability, and performance tuning.
- Kong Ingress Controller Documentation — For teams running Kong on Kubernetes, this covers CRDs, plugin configuration, and integration patterns.
- Building Resilient APIs with Kong Gateway — Kong’s engineering blog with real-world case studies on rate limiting and traffic management at scale.
Building something like this? I’m an AI/systems contractor open to new projects. Book a 30-min call.