📑 Contents Architecture vs Kong / Traefik / Envoy Routes, Services, Upstreams Consumers & Auth Plugin System Plugin Catalog Quick Start (Docker) Standalone Mode Cluster with etcd Kubernetes Ingress Admin API Observability Performance Decision Guide References

What is Apache APISIX?

Apache APISIX is a high-performance, cloud-native API gateway and ingress controller built on OpenResty (Nginx + LuaJIT). It handles north-south traffic (client → backend) and supports east-west service mesh use cases via APISIX's mesh mode.

Unlike Kong (which uses PostgreSQL or Cassandra for config), APISIX uses etcd as its config store, enabling sub-millisecond hot-reload of routes, plugins, and upstreams — no gateway restart needed.

High Performance
Built on Nginx + LuaJIT. Handles millions of RPS with single-digit millisecond latency.
🔌
Plugin System
80+ built-in plugins. Write custom plugins in Lua, WASM (Go/Rust), or via external runners (Java, Python, Go).
🔄
Dynamic Config
Config changes take effect in real-time via etcd watch. Zero downtime updates.
☸️
Kubernetes Native
APISIX Ingress Controller maps K8s Ingress/CRDs to APISIX routes automatically.
🌐
Protocol Support
HTTP/1.1, HTTP/2, HTTP/3 (QUIC), gRPC, WebSocket, Dubbo, MQTT.
🔐
Auth & Security
JWT, Key Auth, OAuth2, OIDC, LDAP, Casbin RBAC, mTLS, IP restrict.
APISIX vs APISIX Ingress Controller Apache APISIX is the gateway engine itself. APISIX Ingress Controller is a Kubernetes operator that watches Ingress/CRD resources and syncs them to an APISIX instance running inside the cluster.

Architecture

APISIX separates the data plane (request handling) from the control plane (config management). In a production cluster, multiple APISIX data plane nodes pull config from a shared etcd cluster.

── Request flow ──────────────────────────────────────
Client  ──HTTPS──▶  APISIX (data plane)  ──▶  Upstream Services
── Config / Control plane ─────────────────────────────
APISIX Dashboard / Admin API  ──writes──▶  etcd cluster
APISIX nodes  ◀──watch──  etcd  (sub-ms config push)
── Key paths in a single APISIX node ─────────────────
Request ──▶ [SSL termination] ──▶ [Route matching] ──▶ [Plugin chain: rewrite → access → proxy → header_filter → body_filter → log] ──▶ [Load balancer → Upstream node] ──▶ Response back to client

Component Roles

ComponentRoleNotes
APISIX (data plane) Processes every API request — routing, plugin execution, load balancing, SSL Stateless; multiple nodes for HA
etcd Source of truth for all config: routes, upstreams, consumers, plugins Run 3-node cluster in production
Admin API REST API on port 9180 for CRUD operations on routes/upstreams/etc. Protected by Admin key; can be disabled
APISIX Dashboard Web UI on port 9000 wrapping the Admin API Separate Docker image; optional
Plugin Runner Sidecar process for running plugins in Java / Python / Go Communicates via Unix socket

Plugin Execution Phases

Every request goes through these Nginx phases. Plugins declare which phases they hook into:

-- Phase order for a proxied request:
init           -- worker startup
rewrite        -- URL rewriting, header manipulation before routing
access         -- auth, rate limiting, IP checks (before upstream call)
before_proxy   -- final chance to modify upstream request
header_filter  -- modify response headers from upstream
body_filter    -- modify response body
log            -- async logging, metrics, tracing (after response sent)
Why etcd? etcd's watch mechanism lets every APISIX node instantly receive config changes without polling. This is what makes route/plugin changes take effect in <100ms cluster-wide — critical for canary deployments and A/B testing.

APISIX vs Kong vs Traefik vs Envoy

Feature APISIX 3.x Kong 3.x Traefik 3.x Envoy / Istio
Engine OpenResty (Nginx + LuaJIT) OpenResty (Nginx + LuaJIT) Go C++ (Envoy)
Config store etcd (dynamic) PostgreSQL / Cassandra In-memory + provider APIs xDS (Istio control plane)
Dynamic config (no restart) ✓ Sub-ms via etcd watch ~ DB polling ✓ Provider watch ✓ xDS
Plugin language Lua, WASM, Java/Python/Go runners Lua, Go (Kong Gateway) Go (middleware) C++, WASM, Ext. authz
Built-in plugins 80+ 60+ 30+ middlewares Filters (limited built-in)
Kubernetes native ✓ Ingress Controller + CRDs ✓ KIC ✓ Native K8s provider ✓ First-class
Service mesh ~ Sidecar mode (experimental) ✗ North-south only ✗ North-south only ✓ Core use case
gRPC / WebSocket
Dashboard (OSS) ✓ (separate container) ✗ (Enterprise only) ✓ Built-in ~ Kiali (Istio)
Performance (raw) Very high (LuaJIT) Very high (LuaJIT) High (Go) Very high (C++)
License Apache 2.0 Apache 2.0 (OSS) / BSL (EE) MIT Apache 2.0
Learning curve Medium (Lua plugins) Medium (similar to APISIX) Low (K8s-native feel) High (Envoy config is complex)
When to pick APISIX over Kong APISIX has better OSS community momentum, sub-millisecond config updates (etcd vs DB polling), a free dashboard, and first-class WASM support. Kong's enterprise tier has richer SaaS features. For greenfield projects in 2025, APISIX is usually the better open-source choice.

Core Concepts: Routes, Services, Upstreams

APISIX's data model has a clear hierarchy. Understanding these six objects covers 90% of day-to-day config.

Object hierarchy

Consumer (API caller identity)
  └── Credentials (key, JWT, OAuth token...)

Global Rule (plugin applied to ALL routes)

Plugin Config (reusable plugin bundle)
  └── referenced by multiple Routes

Route  ──── matches: host + path + method
  ├── plugins: [array of per-route plugin configs]
  ├── service_id → Service (optional shared layer)
  └── upstream_id → Upstream (OR inline upstream)

Service  (shared Route config / plugin set)
  └── upstream_id → Upstream

Upstream (load balancer config)
  └── nodes: { "host:port": weight, ... }
       health-check, retries, timeout, scheme

Route

A Route is the entry point. It matches incoming requests and defines what happens to them.

# POST /apisix/admin/routes/1
{
  "uri": "/api/v1/*",
  "methods": ["GET", "POST"],
  "host": "api.example.com",
  "plugins": {
    "jwt-auth": {},
    "rate-limiting": { "count": 100, "time_window": 60 }
  },
  "upstream_id": "backend-v1"
}

Upstream

An Upstream defines the backend servers and load-balancing strategy. Supports health checks and circuit breaking.

# POST /apisix/admin/upstreams/backend-v1
{
  "name": "backend-v1",
  "type": "roundrobin",          // roundrobin | least_conn | ewma | chash
  "nodes": {
    "svc-a:8080": 1,
    "svc-b:8080": 2             // weight 2 = 2x traffic
  },
  "scheme": "http",
  "timeout": { "connect": 6, "send": 6, "read": 6 },
  "retries": 1,
  "checks": {
    "active": {
      "http_path": "/health",
      "healthy":   { "interval": 5,  "successes": 2 },
      "unhealthy": { "interval": 5,  "http_failures": 3 }
    }
  }
}

Service

A Service is an optional shared layer that bundles a common upstream + plugin set. Multiple routes can reference the same service, avoiding duplication.

# POST /apisix/admin/services/user-svc
{
  "name": "user-service",
  "upstream_id": "backend-v1",
  "plugins": {
    "prometheus": {},
    "cors": { "allow_origins": "*" }
  }
}

Load Balancing Algorithms

TypeBest for
roundrobinDefault; equal-weight distribution
least_connVariable request duration; send to least-busy node
ewmaExponentially Weighted Moving Average latency — picks fastest node
chashConsistent hashing by key (IP, header, query param) — sticky sessions
ip_hashClient IP sticky routing (legacy; prefer chash)

Consumers & Authentication

A Consumer represents an API caller identity. Credentials are attached to Consumers, and plugins can restrict access per Consumer or Consumer Group.

Consumer example — Key Auth

# 1. Create consumer
# POST /apisix/admin/consumers
{
  "username": "alice",
  "plugins": {
    "key-auth": { "key": "my-secret-api-key" }
  }
}

# 2. Enable key-auth on the route
# In the route's plugins block:
{
  "key-auth": {}   // no config needed — just activates the plugin
}

# 3. Client calls API with key in header (default) or query param
curl -H "apikey: my-secret-api-key" https://api.example.com/api/v1/users

Consumer Groups

Consumer Groups let you apply a shared plugin config (e.g., a rate limit tier) to many Consumers at once.

# POST /apisix/admin/consumer_groups/premium-tier
{
  "plugins": {
    "rate-limiting": { "count": 10000, "time_window": 60 }
  }
}

# Assign consumer to group
{
  "username": "alice",
  "group_id": "premium-tier",
  "plugins": { "key-auth": { "key": "..." } }
}

Supported Auth Methods

PluginProtocolNotes
key-authAPI KeyHeader or query param
jwt-authJWTValidates signature + claims; HS256/RS256
basic-authHTTP BasicFor simple use cases / internal tools
oauth2OAuth 2.0Token introspection endpoint
openid-connectOIDCIntegrates with Keycloak, Auth0, Okta…
ldap-authLDAPEnterprise directory lookup
hmac-authHMAC signatureRequest signing (AWS-style)
wolf-rbacRBACRole-based access via Wolf server
casbinPolicy-basedFine-grained authz with Casbin rules

Plugin System

Plugins are the core extensibility mechanism. They can be enabled per-Route, per-Service, or globally (Global Rules). APISIX evaluates plugins in priority order within each execution phase.

Plugin scope hierarchy

Global Rule   (applied to ALL requests, e.g. IP allow-list)
  ▼
Service       (applied to all routes using this service)
  ▼
Route         (most specific; overrides service-level config)
  ▼
Consumer      (credential-level config, e.g. per-consumer rate limit)

Writing a custom Lua plugin

-- /usr/local/apisix/apisix/plugins/my-plugin.lua
local plugin_name = "my-plugin"

local schema = {
  type = "object",
  properties = {
    message = { type = "string", default = "hello" }
  }
}

local _M = {
  version  = 0.1,
  priority = 1000,   -- higher = runs earlier in the same phase
  name     = plugin_name,
  schema   = schema,
}

function _M.access(conf, ctx)
  -- runs in the access phase (before proxying)
  core.response.set_header("X-My-Plugin", conf.message)
end

return _M

External Plugin Runners

For teams who don't want to write Lua, APISIX supports external plugin runners — sidecar processes that communicate via Unix socket (RPC). Available runners:

  • Javaapisix-java-plugin-runner
  • Goapisix-go-plugin-runner
  • Pythonapisix-python-plugin-runner
  • WASM — WebAssembly plugins (Go/Rust compiled to WASM)
Performance note on external runners External runners add a Unix socket RPC round-trip per request phase they hook into (~0.1–0.5ms). For low-latency APIs, prefer Lua plugins. Use runners when you need to reuse existing business logic written in Java/Go/Python.

Plugin Config (reusable bundles)

# Create a reusable plugin config
# POST /apisix/admin/plugin_configs/standard-auth
{
  "plugins": {
    "jwt-auth": {},
    "rate-limiting": { "count": 200, "time_window": 60 },
    "prometheus": {}
  }
}

# Reference in a route (instead of repeating plugin config)
{
  "uri": "/api/v2/*",
  "plugin_config_id": "standard-auth",
  "upstream_id": "backend-v2"
}

Plugin Catalog (Key Plugins)

Authentication

AUTH
jwt-auth
Validates JWT tokens. Supports HS256, RS256, ES256. Attach secrets to Consumers.
AUTH
key-auth
API key in header or query. Simple and fast.
AUTH
openid-connect
OIDC code flow. Works with Keycloak, Auth0, Okta, Dex.
AUTH
basic-auth
HTTP Basic authentication. Validates against Consumer credentials.
AUTH
hmac-auth
AWS-style request signing. Prevents replay attacks.
AUTH
authz-keycloak
Delegates authorization decisions to Keycloak policy enforcer.

Traffic Management

TRAFFIC
rate-limiting
Token bucket rate limiter per consumer / IP / route. Redis-backed for cluster mode.
TRAFFIC
limit-req
Leaky bucket algorithm. Smooths bursts into steady request rate.
TRAFFIC
limit-conn
Limits concurrent connections per key (IP, consumer).
TRAFFIC
traffic-split
Weighted traffic splitting between upstreams. Essential for canary releases.
TRAFFIC
proxy-cache
Disk-based or memory-based response caching. Supports cache keys, TTL, bypass conditions.
TRAFFIC
api-breaker
Circuit breaker. Opens on error threshold, half-opens after cool-down.
TRAFFIC
request-validation
Validates request headers and body against JSON Schema before proxying.

Observability

OBS
prometheus
Exposes /apisix/prometheus/metrics. Scrape-ready for Grafana dashboards.
OBS
opentelemetry
W3C TraceContext propagation. Exports to OTLP collector (Jaeger, Tempo, Zipkin).
OBS
zipkin
Native Zipkin span reporting. Simpler than OTel if Zipkin is your tracer.
OBS
http-logger
Push access logs to any HTTP endpoint (Elasticsearch, Splunk, custom receiver).
OBS
kafka-logger
Async access log shipping to Kafka topics. Low-latency, high-throughput logging.
OBS
skywalking
Apache SkyWalking tracing integration. Popular in Java/Spring ecosystems.

Transformation & Header Manipulation

TX
proxy-rewrite
Rewrite URI, scheme, host, headers before proxying upstream. Essential for path stripping.
TX
response-rewrite
Modify status code, headers, or body in the response. Regex body replace supported.
TX
cors
Handles CORS preflight and response headers. Configurable origins, methods, headers.
TX
grpc-transcode
HTTP/JSON → gRPC transcoding. Expose gRPC services as REST APIs.
TX
redirect
HTTP → HTTPS redirect, or custom 3xx redirect with configurable URI.

Security

SEC
ip-restriction
IP allowlist / denylist. CIDR ranges supported. Global or per-route.
SEC
ua-restriction
Block or allow requests by User-Agent regex. Useful for bot blocking.
SEC
csrf
CSRF token validation for state-changing endpoints.
SEC
consumer-restriction
Restrict route access to specific consumers or consumer groups.
SEC
ext-plugin-pre-req
Delegates auth/policy decisions to an external service (OPA, custom service).

Quick Start with Docker Compose

The fastest way to run APISIX locally with etcd and the Dashboard.

# docker-compose.yml
version: "3"
services:

  etcd:
    image: bitnami/etcd:3.5
    environment:
      ALLOW_NONE_AUTHENTICATION: "yes"
    ports:
      - "2379:2379"

  apisix:
    image: apache/apisix:3.9.0-debian
    volumes:
      - ./config/apisix.yaml:/usr/local/apisix/conf/config.yaml
    ports:
      - "9080:9080"   # HTTP proxy
      - "9443:9443"   # HTTPS proxy
      - "9180:9180"   # Admin API
      - "9091:9091"   # Prometheus metrics
    depends_on:
      - etcd

  dashboard:
    image: apache/apisix-dashboard:3.0.0-centos
    volumes:
      - ./config/dashboard.yaml:/usr/local/apisix-dashboard/conf/conf.yaml
    ports:
      - "9000:9000"
    depends_on:
      - apisix
# config/apisix.yaml — minimal config
apisix:
  node_listen: 9080
  enable_ipv6: false

deployment:
  role: traditional
  role_traditional:
    config_provider: etcd
  etcd:
    host:
      - "http://etcd:2379"
    prefix: /apisix
    timeout: 30

plugin_attr:
  prometheus:
    export_addr:
      ip: "0.0.0.0"
      port: 9091
# Create your first route via Admin API
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
  -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" \
  -X PUT -d '{
    "uri": "/get",
    "name": "test-route",
    "upstream": {
      "type": "roundrobin",
      "nodes": { "httpbin.org:80": 1 }
    }
  }'

# Test it
curl http://127.0.0.1:9080/get
Default Admin API key The default Admin API key is edd1c9f034335f136f87ad84b625c8f1. Change it immediately in production by setting apisix.admin_key in your config.

Standalone Mode (No etcd)

Standalone mode reads config from a static apisix.yaml file on disk. No etcd needed — ideal for simple deployments, local dev, and CI pipelines where dynamic updates aren't required.

# config.yaml — enable standalone mode
deployment:
  role: data_plane
  role_data_plane:
    config_provider: yaml   # reads conf/apisix.yaml
# conf/apisix.yaml — declarative route definitions
routes:
  - uri: /api/hello
    upstream:
      type: roundrobin
      nodes:
        "backend:8080": 1
    plugins:
      rate-limiting:
        count: 100
        time_window: 60
        key_type: remote_addr
        rejected_code: 429

  - uri: /api/users/*
    upstream:
      type: roundrobin
      nodes:
        "user-service:8080": 1
    plugins:
      jwt-auth: {}
      proxy-rewrite:
        regex_uri: ["^/api/users/(.*)", "/$1"]

# Config hot-reload: touch the file or send SIGHUP
# APISIX polls apisix.yaml every 1s in standalone mode
Standalone limitations In standalone mode, you cannot use the Admin API or Dashboard to make changes. All config must be in the YAML file. No Consumer/Plugin Config objects — those must be inlined in routes.

HA Cluster with etcd

Production APISIX deployments run multiple data plane nodes behind a load balancer, all reading from a 3-node etcd cluster for high availability.

Internet │ ▼ [ Load Balancer / NLB ] │ │ ▼ ▼ [ APISIX ] [ APISIX ] ◀── data plane nodes (stateless) │ │ ▼ ▼ [ etcd cluster: 3 nodes ] ◀── config store (leader elected) │ ▼ [ APISIX Dashboard / Admin API ] ◀── config management

etcd production tips

  • Run a 3-node (or 5-node) etcd cluster. etcd uses Raft — it needs a majority quorum to operate.
  • Separate etcd from APISIX data plane nodes — don't run etcd on the same host as the gateway.
  • Enable etcd TLS (etcd-client-cert.pem) if the Admin API is exposed beyond localhost.
  • Back up etcd regularly: etcdctl snapshot save.
  • Tune etcd.timeout in APISIX config if network latency to etcd is high.

APISIX config for HA cluster

deployment:
  role: traditional
  role_traditional:
    config_provider: etcd
  etcd:
    host:
      - "https://etcd-0:2379"
      - "https://etcd-1:2379"
      - "https://etcd-2:2379"
    tls:
      cert: /etc/ssl/etcd-client.pem
      key:  /etc/ssl/etcd-client-key.pem
      verify: true
    prefix: /apisix
    timeout: 30

nginx_config:
  worker_processes: auto
  worker_connections: 10620

Kubernetes: APISIX Ingress Controller

APISIX Ingress Controller (AIC) is a K8s operator that watches Ingress resources and custom CRDs (ApisixRoute, ApisixUpstream, ApisixConsumer) and syncs them to a running APISIX instance.

Install via Helm

# Add chart repo
helm repo add apisix https://charts.apiseven.com
helm repo update

# Install APISIX + Ingress Controller in one chart
helm install apisix apisix/apisix \
  --namespace ingress-apisix \
  --create-namespace \
  --set gateway.type=LoadBalancer \
  --set ingress-controller.enabled=true \
  --set ingress-controller.config.apisix.serviceNamespace=ingress-apisix

Standard Kubernetes Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-api
  annotations:
    kubernetes.io/ingress.class: apisix
    k8s.apisix.apache.org/rewrite-target: /
spec:
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: my-backend-svc
                port:
                  number: 8080

ApisixRoute CRD (more powerful than Ingress)

apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
  name: user-api-route
spec:
  http:
    - name: users
      match:
        hosts:
          - api.example.com
        paths:
          - /api/v1/users*
        methods:
          - GET
          - POST
      backends:
        - serviceName: user-service
          servicePort: 8080
          weight: 100
      plugins:
        - name: jwt-auth
          enable: true
        - name: rate-limiting
          enable: true
          config:
            count: 200
            time_window: 60
            key_type: consumer

ApisixConsumer CRD

apiVersion: apisix.apache.org/v2
kind: ApisixConsumer
metadata:
  name: alice
spec:
  authParameter:
    jwtAuth:
      value:
        key: alice-jwt-key
        secret: my-signing-secret
CRDs vs Standard Ingress Standard Ingress only covers basic routing. Use ApisixRoute CRDs when you need plugins, traffic splitting, or advanced match rules. The AIC watches both — you can mix and match.

Canary deployment with traffic-split

apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
  name: canary-route
spec:
  http:
    - name: canary
      match:
        paths: [/api/v1/*]
      backends:
        - serviceName: backend-stable
          servicePort: 8080
          weight: 90
        - serviceName: backend-canary
          servicePort: 8080
          weight: 10    # 10% traffic to new version

Admin API Reference

The Admin API runs on port 9180 (separate from the proxy port 9080). All operations require the X-API-KEY header.

ResourceEndpointMethods
Routes/apisix/admin/routes/{id}GET PUT POST PATCH DELETE
Services/apisix/admin/services/{id}GET PUT POST PATCH DELETE
Upstreams/apisix/admin/upstreams/{id}GET PUT POST PATCH DELETE
Consumers/apisix/admin/consumers/{username}GET PUT DELETE
Consumer Groups/apisix/admin/consumer_groups/{id}GET PUT DELETE
Plugin Configs/apisix/admin/plugin_configs/{id}GET PUT POST PATCH DELETE
Global Rules/apisix/admin/global_rules/{id}GET PUT POST PATCH DELETE
SSL Certs/apisix/admin/ssls/{id}GET PUT POST DELETE
Plugins (list)/apisix/admin/plugins/listGET
Health/apisix/admin/statusGET

Common Admin API patterns

# List all routes
curl http://127.0.0.1:9180/apisix/admin/routes \
  -H "X-API-KEY: $APISIX_ADMIN_KEY"

# Patch a single field without full replace
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
  -H "X-API-KEY: $APISIX_ADMIN_KEY" \
  -X PATCH \
  -d '{"status": 0}'   # 0 = disable route, 1 = enable

# Upload TLS certificate
curl http://127.0.0.1:9180/apisix/admin/ssls/1 \
  -H "X-API-KEY: $APISIX_ADMIN_KEY" \
  -X PUT \
  -d "{
    \"snis\": [\"api.example.com\"],
    \"cert\": \"$(cat cert.pem)\",
    \"key\":  \"$(cat key.pem)\"
  }"

# Check node health
curl http://127.0.0.1:9180/apisix/admin/upstreams/backend-v1/health \
  -H "X-API-KEY: $APISIX_ADMIN_KEY"

Observability

Prometheus metrics

Enable the prometheus plugin globally and scrape :9091/apisix/prometheus/metrics.

# Global rule — applies Prometheus to all routes
# POST /apisix/admin/global_rules/prometheus
{
  "plugins": {
    "prometheus": {
      "prefer_name": true   // use route name in labels instead of ID
    }
  }
}

Key metrics exposed:

  • apisix_http_requests_total — request count by route, status, method
  • apisix_http_latency_bucket — latency histogram (request/upstream)
  • apisix_bandwidth — bytes in/out per route
  • apisix_nginx_http_current_connections — active connections
  • apisix_upstream_status — health check results per upstream node

Distributed Tracing with OpenTelemetry

# apisix.yaml — global OTel config
plugin_attr:
  opentelemetry:
    resource:
      service.name: "apisix"
    collector:
      address: "otel-collector:4317"
      request_timeout: 3
    set_ngx_var: false
    batch_span_processor:
      max_export_batch_size: 512
      inactive_timeout: 2

# Enable per-route
{
  "opentelemetry": {
    "sampler": { "name": "parentbased_traceidratio", "options": { "fraction": 0.1 } }
  }
}

Access log shipping to Kafka

{
  "kafka-logger": {
    "broker_list": { "kafka-broker:9092": 1 },
    "kafka_topic": "apisix-access-logs",
    "timeout": 3,
    "include_req_body": false
  }
}

Performance

APISIX is one of the highest-throughput API gateways available. Its performance comes from OpenResty's non-blocking I/O and LuaJIT's JIT compilation.

Gateway~Throughput (RPS)~P99 LatencyNotes
APISIX 3.x (no plugins)>200,000 RPS<2msSingle node, simple routing
APISIX 3.x (jwt-auth + rate-limit)~80,000–120,000 RPS2–5msDepends on plugin count
Kong 3.xSimilar rangeSimilarSame OpenResty base
Traefik 3.x~50,000–100,000 RPS3–8msGo GC pauses at high load
Nginx (raw)>500,000 RPS<1msBaseline — no gateway features

Tuning tips

  • Set worker_processes: auto to use all CPU cores.
  • Increase worker_connections to 10620+ for high concurrency.
  • Use Redis-backed rate limiting (policy: redis) only when you need cluster-wide counts — local policy is faster for single-node or when per-node limits are acceptable.
  • Prefer Lua plugins over external runners for latency-sensitive routes.
  • Use proxy-cache to absorb repeated identical requests to slow upstreams.
  • Disable unused plugins globally — even unexecuted plugins add microseconds to plugin chain resolution.
# nginx_config tuning in apisix config.yaml
nginx_config:
  worker_processes: auto
  worker_rlimit_nofile: 65535
  event:
    worker_connections: 16384
  http:
    keepalive_timeout: 60s
    client_max_body_size: 0
    gzip: "on"
    real_ip_header: "X-Forwarded-For"

Decision Guide

Use APISIX when…
  • You need dynamic config hot-reload without restarts — canary deployments, feature flags at the gateway layer
  • You want a fully open-source API gateway with a free web dashboard
  • Your team is comfortable with Lua or you need plugin logic in Java/Go/Python via runners
  • You're running Kubernetes and want Ingress + CRD-based routing with advanced plugins
  • You need gRPC transcoding, MQTT proxying, or Dubbo support
  • You need high throughput + low latency — APISIX's LuaJIT base is hard to beat
Consider Traefik instead when…
  • You want zero config for K8s Ingress — Traefik's Docker/K8s auto-discovery is simpler to set up
  • Your team is Go-first and wants to write middleware in Go without a sidecar
  • You don't need rich plugin ecosystem — just routing, TLS, and basic rate limiting
Consider Envoy / Istio instead when…
  • You need a service mesh (east-west mTLS between services, not just north-south)
  • You're already using Istio and want gateway + mesh in one platform
  • You need xDS-based dynamic config compatible with the broader Envoy ecosystem
Quick reference — common tasks
  • Canary deploytraffic-split plugin or ApisixRoute weighted backends
  • Rate limit by userrate-limiting with key_type: consumer + Redis
  • JWT validationjwt-auth plugin + Consumer with secret
  • Strip /api prefixproxy-rewrite with regex_uri
  • Circuit breakerapi-breaker plugin on upstream route
  • gRPC as RESTgrpc-transcode plugin with proto file
  • Block bad IPsip-restriction as Global Rule
  • Trace all requestsopentelemetry as Global Rule with sampling

References

Official documentation and community resources. All links verified as of 2026-06-27.