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

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 and apisix/cli/apisix.lua, then executes luajit <apisix.lua> <command args>
  • apisix/cli/apisix.lua: Sets up Lua module search paths, then delegates to apisix.cli.ops
  • apisix/cli/ops.lua: Implements init / start / stop / restart / reload commands

2.2 nginx.conf Generation

When apisix start is executed, ops.lua’s init() function:

  1. Reads YAML config → validates schema via apisix/cli/schema.lua
  2. Generates conf/nginx.conf via apisix/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):

  1. Random seed, LRU cache, DNS resolver
  2. discovery.init_worker() — Service discovery
  3. balancer.init_worker() — Load balancer
  4. admin.init_worker() — Admin API
  5. plugin.load() — Load all plugins (sorted by priority)
  6. router.http_init_worker() — HTTP routing table initialization
  7. require("apisix.http.service").init_worker() — Service object initialization
  8. 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 route
  • upstream_conf — Upstream configuration
  • plugins — List of plugins to execute
  • consumer — Consumer information
  • var — 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 → call load_plugin() for each → sort by priority descending
  • load_plugin(name): Require plugin module → validate priority/version/schema → call plugin.init() → inject _meta field
  • run_plugin(phase, ...): Execute plugin chain by phase
  • filter_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/unload
  • check_schema(conf, schema_type) — Custom schema validation
  • rewrite(conf, ctx) / access(conf, ctx) — Request processing
  • header_filter(conf, ctx) / body_filter(conf, ctx) — Response processing
  • delayed_body_filter(conf, ctx) — Delayed body filtering
  • log(conf, ctx) — Log reporting
  • api() / 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-robin
  • chash.lua — Consistent hashing
  • ewma.lua — Exponentially weighted moving average (least latency)
  • least_conn.lua — Least connections
  • priority.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 functions
  • t/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 tests
  • t/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]

Following this order will help you gradually build a complete understanding of the system:

Phase 1: Skeleton (Build the Big Picture)

  1. bin/apisix — Startup script, understand how OpenResty is launched
  2. apisix/cli/apisix.lua + apisix/cli/ops.lua — CLI command handling, understand init/start command implementation
  3. apisix/init.lua — Main entry point, focus on http_init_worker() initialization order and http_access_phase() request flow

Phase 2: Core Modules (Understand the Infrastructure)

  1. apisix/core.lua — Core module aggregation entry, understand available core capabilities
  2. apisix/core/ctx.lua — Request context, understand api_ctx creation/release mechanism
  3. apisix/core/config_etcd.lua — etcd config provider, understand how config is read and hot-reloaded
  4. apisix/core/lrucache.lua — Caching mechanism
  5. apisix/core/request.lua + apisix/core/response.lua — Request/response operation wrappers

Phase 3: Core Engine (Understand Key Pipelines)

  1. apisix/router.lua + apisix/http/router/radixtree_uri.lua — Route matching mechanism
  2. apisix/plugin.lua — Plugin engine, understand plugin loading, filtering, and execution lifecycle
  3. apisix/upstream.lua + apisix/balancer.lua — Upstream management and load balancing
  4. apisix/http/service.lua — Route → Service config inheritance logic

Phase 4: Admin API (Understand the Control Plane)

  1. apisix/admin/init.lua — Admin API route dispatch
  2. apisix/admin/resource.lua — Generic CRUD base class
  3. apisix/admin/routes.lua — Use Route CRUD as an example to understand specific resource implementation

Phase 5: Deep Dive into Plugins (Learn by Doing)

  1. apisix/plugins/example-plugin.lua — Plugin development template
  2. Pick a simple plugin you’re interested in (recommended: key-auth.lua or limit-count.lua)
  3. Read apisix/plugins/ai-proxy.lua — Understand complex plugin structure and AI gateway capabilities

Phase 6: Extended Topics

  1. apisix/stream/ — Layer 4 proxy subsystem
  2. apisix/discovery/ — Service discovery (consul/nacos/eureka, etc.)
  3. apisix/secret/ — Secret management
  4. t/ — 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.

Read More

Nginx Source Code Reading Guide

【2026-07-23】A systematic guide to reading Nginx source code - from environment setup and core data structures to process model and HTTP request handling