Built-In Variables
Built-in variables in APISIX are pre-defined variables that can be directly referenced in configurations. They are often used in plugin configurations, route matching, and log customization.
APISIX supports three types of built-in variables:
- NGINX Variables
- APISIX Variables
- Custom Variables
These variables are evaluated in a given order.
NGINX Variables
NGINX provides a set of variables that can be used to access various request-specific information.
Commonly used variables include:
upstream_addrremote_addrrequest_uriserver_nameurihttp_user_agent
See the complete list of NGINX variables for more information.
APISIX Variables
In addition to NGINX variables, APISIX offers a variety of built-in variables:
| Variable Name | Description |
|---|---|
post_arg_* | HTTP POST form data when the content type is application/x-www-form-urlencoded. The asterisk is to be replaced with the actual name of the POST form data. |
post_arg.* | HTTP POST body parameter when the content type is application/json, application/x-www-form-urlencoded, or multipart/form-data. The asterisk is to be replaced with the actual name of the POST parameter. Supports JSON path-like selection, such as post_arg.model.version and post_arg.messages[*].content[*].type. |
arg_* | URL query string. The asterisk is to be replaced with the actual query parameter name. |
uri_param_* | URL parameter when APISIX uses the radixtree_uri_with_parameter router. The asterisk is to be replaced with the actual query parameter name. |
http_* | HTTP request header. The asterisk is to be replaced with the actual name of the header. |
cookie_* | Request cookie. The asterisk is to be replaced with the actual name of the cookie. |
balancer_ip | Upstream server IP. |
balancer_port | Upstream server port. |
consumer_name | Consumer username. |
consumer_group_id | Consumer group ID. |
graphql_name | GraphQL operation name. |
graphql_operation | GraphQL operation type. |
graphql_root_fields | GraphQL root fields. |
rate_limiting_info | JSON rate-limiting result generated by the limit-count plugin. Empty before the plugin runs. |
route_id | Route ID. |
route_name | Route name. |
service_id | Service ID. |
service_name | Service name. |
upstream_unresolved_host | Host or IP address of the selected upstream node before DNS resolution. For a node configured as httpbin.org, this variable remains httpbin.org while balancer_ip contains the resolved address. |
resp_body | HTTP response body. |
mqtt_client_id | Client ID in MQTT protocol. |
redis_cmd_line | Redis command. |
rpc_time | RPC request round-trip time. |
Log Limit Count Results
The limit-count plugin sets rate_limiting_info after it evaluates a request. Other rate-limiting plugins do not populate this variable. Before limit-count runs, or on a route without the plugin, the value is an empty string.
The JSON value contains these fields:
| Field | Description |
|---|---|
rate_limiting_key | Effective counter key used for the request. |
rate_limiting_limit | Configured request limit. |
rate_limiting_remaining | Remaining quota after the current request. |
rate_limiting_reset | Seconds until the counter resets. |
To include the value in access logs, add it to the access-log format in config.yaml:
nginx_config:
http:
access_log_format: >-
$remote_addr "$request" $status $rate_limiting_info
Reload APISIX, configure limit-count on a route, and send a request. The access log should contain a value similar to the following:
{\x22rate_limiting_key\x22:\x22/apisix/routes/limit-route:1729132800:example.com\x22,\x22rate_limiting_limit\x22:100,\x22rate_limiting_remaining\x22:99,\x22rate_limiting_reset\x22:60}
The default NGINX log escaping represents quotation marks as \x22. Decode the escaped value before parsing it as JSON in a downstream log processor.
Treat the key as an implementation value for correlation and troubleshooting. Do not parse its internal segments as a stable public format.
Custom Variables
You can also register your own variables and use them as built-in variables. For instance, you can use custom variables to customize log format in logging plugins, or use them as keys in rate limiting plugins.
Example
The following example demonstrates two approaches for custom variable registration and how you can leverage the variable to obtain information from a route, subsequently logging the information to a remote server.
Create a Service
Create a service to configure http-logger plugin and upstream:
curl "http://127.0.0.1:9180/apisix/admin/services" -X PUT \
-H 'X-API-KEY: ${ADMIN_API_KEY}' \
--data-binary @- <<EOF
{
"id":"srv_custom_var",
"plugins": {
"http-logger": {
"uri": "${REMOTE_SERVER_ADDR}"
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
}
}
}
EOF
Register a Custom Variable
You can choose to register the custom variable in the source code or use the serverless plugins.
Method 1: In the Source Code
Add the following snippet to your custom Lua file and source it to register a custom variable named a6_route_labels. The variable represents the value of labels in a request to a route, if available:
local core = require "apisix.core"
core.ctx.register_var("a6_route_labels", function(ctx)
local route = ctx.matched_route and ctx.matched_route.value
if route and route.labels then
return route.labels
end
return nil
end)
Start or reload APISIX accordingly. If APISIX is already running, send a PUT request to /apisix/admin/plugins/reload to hot reload the plugins for changes to take effect.
While the snippet can technically be added anywhere the code is sourced, exercise caution when modifying the APISIX core codebase to avoid any negative impact on the standard functionalities.
It is recommended to keep your custom Lua code in a separate directory and source it by configuring extra_lua_path and extra_lua_cpath in the config.yaml configuration file.
For more information, see create Lua plugin guide.
Method 2: In the serverless Plugins
You can also register a custom variable using the serverless-pre-function or serverless-post-function serverless function plugins. These plugins run serverless functions before or after a specified execution phase, and you can register custom variables in these functions.
Add the serverless-pre-function plugin to the previously created service, where the function registers the custom variable a6_route_labels:
curl "http://127.0.0.1:9180/apisix/admin/services/srv_custom_var" -X PATCH \
-H 'X-API-KEY: ${ADMIN_API_KEY}' \
-d '{
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function()
local core = require \"apisix.core\"
core.ctx.register_var(\"a6_route_labels\", function(ctx)
local route = ctx.matched_route and ctx.matched_route.value
if route and route.labels then
return route.labels
end
return nil
end);
end"
]
}
}
}'
Method 3: In _meta.pre_function of Plugins
If you prefer to register the custom variable in the plugin without using the serverless plugin, you can use _meta.pre_function to run custom code before each phase of plugin execution.
The following example will show you how to declare a _meta.pre_function in the proxy-rewrite plugin to extract the user_id in the request path, register it as a variable, and use it to compose the new request path.
To use parameters in the route URI, first set the router to radixtree_uri_with_parameter in the configuration file:
apisix:
router:
http: radixtree_uri_with_parameter
Then reload APISIX for changes to take effect.
Create a route to the httpbin service to examine the rewritten path:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "pre-func-route",
"uri": "/anything/:user_id/hello",
"plugins": {
"proxy-rewrite": {
"_meta": {
"pre_function": "
return function(conf, ctx)
local core = require \"apisix.core\"
core.ctx.register_var(\"user_id\", function(ctx) return ctx.curr_req_matched.user_id end)
end"
},
"uri": "/anything/$user_id/world"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
❶ Match requests to /anything/:user_id/hello where user_id is a parameter.
❷ Customize the _meta.pre_function to extract the user_id value from the requested path and save it to a variable of the same name.
❸ Rewrite the request path to /anything/$user_id/world, where $user_id will be replaced by the variable value.
Send a request to the route:
curl -i "http://127.0.0.1:9080/anything/johndoe/hello"
You should observe the following response, showing the request path has been rewritten partially with the user_id:
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "text/html..."
...
},
"json": null,
"method": "GET",
"origin": "127.0.0.1, 59.71.xxx.xxx",
"url": "http://127.0.0.1/anything/johndoe/world"
}
Configure Log Format
Create a plugin metadata object to configure log format for all http-logger instances:
curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/http-logger" -X PUT \
-H 'X-API-KEY: ${ADMIN_API_KEY}' \
-d '{
"log_format": {
"host": "$host",
"client_ip": "$remote_addr",
"labels": "$a6_route_labels"
}
}'
❶ host and remote_addr: NGINX variables.
❷ a6_route_labels: custom variable.
Create a Route in Service
Create a route in the service:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H 'X-API-KEY: ${ADMIN_API_KEY}' \
-d '{
"id":"route_custom_var",
"uri":"/get",
"service_id": "srv_custom_var",
"labels": {
"key": "test_a6_route_labels"
}
}'
❶ service_id: corresponds to the previously created service.
❷ labels: route information to be logged with the custom variable.
Verify Custom Variable Registration
Send a request to verify that the custom variable logs the labels information in the route:
curl "http://127.0.0.1:9080/get"
You should see a log entry in your remote server created by a POST request with a body similar to the following:
[
{
"labels": {
"key": "test_a6_route_labels"
},
"service_id": "srv_custom_var",
"client_ip": "172.21.0.1",
"route_id": "route_custom_var",
"host": "127.0.0.1"
}
]
This verifies the custom variable was registered and it logs the labels information in a route successfully.
Evaluation Order
APISIX evaluates variables in the given order:
- Custom Variables
- APISIX Variables
- NGINX Variables
If a variable is successfully sourced in custom variables, APISIX will not continue to look in APISIX variables or NGINX variables.
In other words, custom variables will overwrite variables of the same names defined in APISIX variables or NGINX variables, to better meet requirements of your specific use cases.
Variable Syntax
A valid variable name can include letters, digits, underscores (_), and periods (.).
Escaped variables with a backslash (\) are not treated as variables, for example, \$variable_name.
Simple and Braced Forms
A variable can be referenced in two forms:
$variable_name${variable_name}
Both forms are supported; however, the braced form is required in certain contexts to ensure correct parsing.
The unbraced form $variable is valid when the following character cannot be part of a variable name. For example, the following forms are equivalent:
$http_hostand${http_host}$arg_username-$arg_useridand${arg_username}-${arg_userid}
When a variable is followed by a character that could belong to a variable name, the parser will incorrectly interpret it as a longer variable name. For example, with https://$http_baseurl.com, the parser would treat the entire string http_baseurl.com as the variable, which is incorrect. In this case, you should use the braced form https://${http_baseurl}.com to clearly delimit the variable.
You would also need the braced form if you use the ?? operator.
Default Values with ??
You can specify a default value for a variable using the ?? operator. If the variable is not defined, the value after the operator will be used.
| Example | Behavior |
|---|---|
${http_username ?? anonymous} | If the HTTP request header username is defined, its value is used; otherwise the string anonymous is used. |
${http_count ?? 10} | If the HTTP request header count is defined, its value is used; otherwise the string 10 is used. |