Apache APISIX Source Code Reading Guide
Categories: APISIX
Apache APISIX Source Code Reading Guide
Preface
Apache APISIX is a dynamic, high-performance API gateway built on OpenResty (Nginx + LuaJIT). This guide helps developers quickly build a holistic understanding of the APISIX source code structure and dive into key modules in a logical order.
Recommended prerequisites:
- Familiarity with Nginx/OpenResty request processing phases (rewrite → access → content → header_filter → body_filter → log)
- Basic knowledge of Lua syntax and module system
- Understanding of etcd basics (etcd is APISIX’s default configuration center)
1. Top-Level Project Structure
apisix/
├── apisix/ # Lua core source (the heart of the project)
│ ├── core/ # Foundation libraries (logging, JSON, config, request/response, cache, etc.)
│ ├── admin/ # Admin API implementation (CRUD operations)
│ ├── plugins/ # HTTP plugins (90+ plugins)
│ ├── http/ # HTTP submodules (route matcher, etc.)
│ ├── stream/ # Layer 4 proxy (TCP/UDP)
│ ├── control/ # Control API (internal management interface)
│ ├── discovery/ # Service discovery (Consul, Nacos, Eureka, etc.)
│ ├── balancer/ # Load balancing algorithms
│ ├── secret/ # Secret management backends
│ ├── utils/ # Utility modules
│ ├── cli/ # CLI tools (start/stop, config generation)
│ └── init.lua # Main entry point, defines all OpenResty phase hooks
├── bin/apisix # Shell startup script
├── conf/ # Runtime configuration
│ ├── config.yaml # User configuration
│ ├── config-default.yaml # Default configuration
│ └── ...
├── t/ # Perl test suite (Test::Nginx)
│ ├── admin/ # Admin API tests
│ ├── plugin/ # Plugin tests (250+ files)
│ ├── core/ # Core module tests
│ ├── lib/ # Test helper libraries
│ └── ...
├── docs/ # Documentation (en + zh)
└── Makefile # Build/deploy/test commands
2. Startup Flow (Recommended Starting Point)
This is the entry point for understanding the entire system. Following the startup chain from end to end builds a holistic view of the system skeleton.
2.1 Shell Entry → Lua CLI
bin/apisix ──→ apisix/cli/apisix.lua ──→ apisix/cli/ops.lua
bin/apisix(Shell script, ~50 lines): Locates OpenResty andapisix/cli/apisix.lua, then executesluajit <apisix.lua> <command args>apisix/cli/apisix.lua: Sets up Lua module search paths, then delegates toapisix.cli.opsapisix/cli/ops.lua: Implementsinit/start/stop/restart/reloadcommands
2.2 nginx.conf Generation
When apisix start is executed, ops.lua’s init() function:
- Reads YAML config → validates schema via
apisix/cli/schema.lua - Generates
conf/nginx.confviaapisix/cli/ngx_tpl.lua(nginx config template engine)
2.3 Worker Initialization
The generated nginx.conf specifies the Lua entry point as apisix/init.lua, which defines the complete request processing lifecycle:
-- Key functions defined in init.lua
http_init(args) -- Global initialization (runs once)
http_init_worker() -- Per-worker process initialization
http_access_phase() -- Request access phase (core of route matching and plugin execution)
http_header_filter_phase()
http_body_filter_phase()
http_log_phase() -- Logging/reporting phase
Initialization order in http_init_worker() (worth noting):
- Random seed, LRU cache, DNS resolver
discovery.init_worker()— Service discoverybalancer.init_worker()— Load balanceradmin.init_worker()— Admin APIplugin.load()— Load all plugins (sorted by priority)router.http_init_worker()— HTTP routing table initializationrequire("apisix.http.service").init_worker()— Service object initialization- Watch for config changes (etcd watch) for hot reload
3. Core Module System (apisix/core/)
apisix/core.lua is a Facade module that aggregates all core submodules into a single core table:
| Module | File | Responsibility |
|---|---|---|
core.log |
core/log.lua |
Log output (warn/error/info/debug) |
core.json |
core/json.lua |
JSON encode/decode with lazy encoding optimization |
core.table |
core/table.lua |
Table utility functions (deepcopy, merge, etc.) |
core.request |
core/request.lua |
Request header/body read/write |
core.response |
core/response.lua |
Response header setting, exit, CORS |
core.schema |
core/schema.lua |
JSON Schema validator wrapper |
core.config |
core/config_etcd.lua / core/config_yaml.lua |
Config providers (etcd / local YAML / xDS) |
core.lrucache |
core/lrucache.lua |
LRU cache with TTL support |
core.ctx |
core/ctx.lua |
Request context management (tablepool reuse) |
core.etcd |
core/etcd.lua |
etcd client wrapper |
core.string |
core/string.lua |
String utility functions |
core.id |
core/id.lua |
ID generator (snowflake ID support) |
core.dns.client |
core/dns/ |
DNS client |
core.pubsub |
core/pubsub.lua |
Publish/subscribe abstraction |
core.event |
core/event.lua |
Inter-worker event system |
Key design pattern: All modules access a unified core reference via require("apisix.core"), avoiding scattered dependencies.
4. Request Processing Flow (The Core Pipeline)
When a user request reaches APISIX, it goes through the following phases (all defined in apisix/init.lua):
Phase 1: http_access_phase() — Access and Route Matching
1. HTTPS client certificate verification
2. Debug dynamic debugging check
3. URI normalization (trailing slash handling, servlet path processing)
4. X-Forwarded-* header processing
5. Router matching → find the matching Route
6. No matching Route → execute Global Rules → return 404
7. Config merging:
plugin_config_id → service_id → consumer → consumer_group
8. Execute Global Rules
9. If script exists → execute script
10. Otherwise → filter plugins → execute rewrite phase plugins → access phase plugins in order
11. handle_upstream():
- Get upstream config via upstream_id or inline upstream
- Load balancer selects a backend node
- Execute before_proxy phase
- Proxy request to upstream
Phases 2/3: Header/Body Filtering
header_filter → set Server header, upstream status header → execute header_filter plugins
body_filter → execute body_filter plugins & delayed_body_filter plugins
Phase 4: http_log_phase() — Log Reporting
Complete tracing span → execute log phase plugins → passive health check → release api_ctx
Key Data Structure: api_ctx
Each request allocates an api_ctx table from tablepool, carrying:
matched_route— The matched routeupstream_conf— Upstream configurationplugins— List of plugins to executeconsumer— Consumer informationvar— Nginx variable snapshot
This table spans all phases and is released back to tablepool at the end of the log phase.
5. Plugin System (apisix/plugin.lua + apisix/plugins/)
5.1 Plugin Loading Mechanism
apisix/plugin.lua is the plugin engine, with core functions:
load(): Read configured plugin list → callload_plugin()for each → sort by priority descendingload_plugin(name): Require plugin module → validate priority/version/schema → callplugin.init()→ inject_metafieldrun_plugin(phase, ...): Execute plugin chain by phasefilter_plugins(user_plugins, conf_version): Filter plugins to execute based on Route config
5.2 Plugin Interface Specification
Each plugin module exports the following fields (reference: apisix/plugins/example-plugin.lua):
local plugin_name = "example-plugin"
local _M = {
version = 0.1, -- Plugin version (required)
priority = 0, -- Execution priority (required, higher runs first)
name = plugin_name, -- Plugin name
schema = {}, -- JSON Schema definition (required)
type = 'auth', -- Plugin type (optional, auth type has special handling)
}
Lifecycle hooks (all optional):
init()/destroy()— Called on load/unloadcheck_schema(conf, schema_type)— Custom schema validationrewrite(conf, ctx)/access(conf, ctx)— Request processingheader_filter(conf, ctx)/body_filter(conf, ctx)— Response processingdelayed_body_filter(conf, ctx)— Delayed body filteringlog(conf, ctx)— Log reportingapi()/control_api()— Register additional Admin/Control API endpoints
5.3 Plugin Priority System
Plugins execute in descending priority order. Reference priorities for key plugins:
| Priority Range | Typical Plugins | Description |
|---|---|---|
| 4000+ | ip-restriction, referer-restriction | Security blocking |
| 3000-3999 | cors, csrf, fault-injection | Security/testing |
| 2500-2999 | key-auth, jwt-auth, basic-auth | Authentication |
| 1000-1999 | limit-count, limit-conn, limit-req | Rate limiting |
| 500-999 | proxy-rewrite, response-rewrite | Rewriting |
| 1-499 | Logging plugins, prometheus | Observability |
5.4 Plugin Category Overview
| Category | Representative Plugins |
|---|---|
| Authentication | key-auth, jwt-auth, basic-auth, hmac-auth, openid-connect, forward-auth |
| Security | ip-restriction, ua-restriction, cors, csrf, uri-blocker, api-breaker |
| Rate Limiting | limit-count, limit-conn, limit-req, traffic-split |
| Rewrite | proxy-rewrite, redirect, response-rewrite, proxy-mirror |
| Serverless | serverless-pre-function, serverless-post-function |
| AI | ai-proxy, ai-prompt-decorator, ai-prompt-guard, ai-rag, ai-rate-limiting |
| Logging | kafka-logger, http-logger, syslog, elasticsearch-logger, loki-logger, etc. |
| Observability | prometheus, zipkin, skywalking, opentelemetry, datadog |
| Integration | aws-lambda, azure-functions, grpc-transcode, grpc-web, dubbo-proxy |
6. Admin API and CRUD System (apisix/admin/)
6.1 Architecture
HTTP Request → admin/init.lua (Token auth + route dispatch) → resource.lua (generic CRUD) → etcd
apisix/admin/init.lua defines the mapping from resources to handler modules:
| Resource | Handler Module | Purpose |
|---|---|---|
| routes | admin/routes.lua | Route management |
| services | admin/services.lua | Service management |
| upstreams | admin/upstreams.lua | Upstream management |
| consumers | admin/consumers.lua | Consumer management |
| ssls | admin/ssl.lua | SSL certificate management |
| global_rules | admin/global_rules.lua | Global rules |
| plugin_configs | admin/plugin_config.lua | Plugin config reuse |
| stream_routes | admin/stream_routes.lua | Layer 4 routes |
| secrets | admin/secrets.lua | Secret management |
6.2 Generic CRUD Pattern (admin/resource.lua)
This is a classic Template Method pattern. Each resource module is created via resource.new({...}) and automatically gets standard GET/PUT/POST/DELETE/PATCH implementations. Differences between resources are injected through schema, validator, id_schema and other config options.
7. Routing System (apisix/router.lua + apisix/http/router/)
7.1 Router Implementations
APISIX supports 3 HTTP router implementations (based on lua-resty-radixtree):
| Implementation | Match Criteria | File |
|---|---|---|
radixtree_uri |
URI only | http/router/radixtree_uri.lua |
radixtree_host_uri |
Host + URI | http/router/radixtree_host_uri.lua |
radixtree_uri_with_parameter |
URI + Parameters | http/router/radixtree_uri_with_parameter.lua |
Additionally:
- SSL routing:
ssl/router/radixtree_sni.lua(SNI-based matching) - Stream routing: IP:Port-based matching
7.2 Route → Service → Upstream Hierarchy
Route ──optional ref──→ Service ──optional ref──→ Upstream
│ │ │
└── Defines URI/Host └── Shared common └── Backend node pool
matching rules config (plugins, etc.) (load balancing config)
Config merge order: plugin_config → consumer → consumer_group → route → service
8. Load Balancing (apisix/balancer.lua + apisix/balancer/)
balancer.lua is the load balancing dispatch center, responsible for creating balancer objects and selecting appropriate backend nodes during request processing.
Supported algorithms (apisix/balancer/):
roundrobin.lua— Weighted round-robinchash.lua— Consistent hashingewma.lua— Exponentially weighted moving average (least latency)least_conn.lua— Least connectionspriority.lua— Priority-based
9. Config Management and Hot Reload
9.1 Config Provider Abstraction
APISIX supports three config sources, switchable via config_provider in config.yaml:
- etcd (
core/config_etcd.lua): Default mode, real-time hot reload via etcd watch - yaml (
core/config_yaml.lua): Standalone mode, reads from local YAML/JSON files - xDS (
core/config_xds.lua): Integrates with Envoy xDS control plane
All three providers implement the same interface:
init() → init_worker() → values(key) → conf_version()
9.2 etcd Hot Reload Flow
etcd PUT /routes/xxx → core/config_etcd.lua watch callback
→ Route table rebuild → New requests use new routes (no Nginx reload needed)
The same applies to Service, Upstream, Plugin, SSL certificates, and all other config.
10. Testing System (t/)
APISIX uses the Perl Test::Nginx::Socket::Lua testing framework.
Bootstrap files:
t/APISIX.pm— Test base config and helper functionst/lib/— Test helper libraries
Directory structure:
t/admin/— Admin API CRUD tests (60+ files)t/plugin/— Plugin tests (250+ files)t/core/— Core module tests (35+ files)t/cli/— CLI testst/stream-node/,t/stream-plugin/— Layer 4 proxy tests
Test case structure example:
use t::APISIX;
use Test::Nginx::Socket::Lua;
run_tests();
__DATA__
=== TEST 1: Test description
--- config
location /t {
content_by_lua_block {
-- Test logic
}
}
--- response_body
Expected output
--- no_error_log
[error]
11. Recommended Reading Order
Following this order will help you gradually build a complete understanding of the system:
Phase 1: Skeleton (Build the Big Picture)
bin/apisix— Startup script, understand how OpenResty is launchedapisix/cli/apisix.lua+apisix/cli/ops.lua— CLI command handling, understand init/start command implementationapisix/init.lua— Main entry point, focus onhttp_init_worker()initialization order andhttp_access_phase()request flow
Phase 2: Core Modules (Understand the Infrastructure)
apisix/core.lua— Core module aggregation entry, understand available core capabilitiesapisix/core/ctx.lua— Request context, understandapi_ctxcreation/release mechanismapisix/core/config_etcd.lua— etcd config provider, understand how config is read and hot-reloadedapisix/core/lrucache.lua— Caching mechanismapisix/core/request.lua+apisix/core/response.lua— Request/response operation wrappers
Phase 3: Core Engine (Understand Key Pipelines)
apisix/router.lua+apisix/http/router/radixtree_uri.lua— Route matching mechanismapisix/plugin.lua— Plugin engine, understand plugin loading, filtering, and execution lifecycleapisix/upstream.lua+apisix/balancer.lua— Upstream management and load balancingapisix/http/service.lua— Route → Service config inheritance logic
Phase 4: Admin API (Understand the Control Plane)
apisix/admin/init.lua— Admin API route dispatchapisix/admin/resource.lua— Generic CRUD base classapisix/admin/routes.lua— Use Route CRUD as an example to understand specific resource implementation
Phase 5: Deep Dive into Plugins (Learn by Doing)
apisix/plugins/example-plugin.lua— Plugin development template- Pick a simple plugin you’re interested in (recommended:
key-auth.luaorlimit-count.lua) - Read
apisix/plugins/ai-proxy.lua— Understand complex plugin structure and AI gateway capabilities
Phase 6: Extended Topics
apisix/stream/— Layer 4 proxy subsystemapisix/discovery/— Service discovery (consul/nacos/eureka, etc.)apisix/secret/— Secret managementt/— Test writing, understand features in reverse through tests
12. Key Design Patterns Summary
| Pattern | Where It Appears | Description |
|---|---|---|
| Facade | apisix/core.lua |
Aggregates all core submodules, unified access point |
| Template Method | apisix/admin/resource.lua |
Generic CRUD base class, submodules inject differentiated config |
| Strategy | apisix/router.lua / apisix/balancer.lua |
Pluggable routing/load balancing implementations |
| Plugin Lifecycle | apisix/plugin.lua + apisix/plugins/*.lua |
Sorted by priority, executed by phase |
| Observer | etcd watch in apisix/core/config_etcd.lua |
Config changes auto-trigger hot reload |
| Object Pool | tablepool + apisix/core/ctx.lua |
Reuse api_ctx tables to reduce GC pressure |
| Provider Abstraction | core/config_etcd.lua / core/config_yaml.lua / core/config_xds.lua |
Unified config interface, swappable backends |
13. Development Environment Setup (Quick Reference)
# Install dependencies
make deps
# Start APISIX
make run
# Stop
make stop
# Run tests
make test
# Run specific tests
prove -I t/ t/plugin/key-auth.t
# Code linting
make lint
It is recommended to read alongside the Apache APISIX Official Documentation and in-source comments. When you encounter problems, the test cases in the
t/directory are the best reference material for understanding each feature.