# 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](#evaluation-order).

## NGINX Variables[​](#nginx-variables "Direct link to NGINX Variables")

NGINX provides a set of variables that can be used to access various request-specific information.

Commonly used variables include:

* `upstream_addr`
* `remote_addr`
* `request_uri`
* `server_name`
* `uri`
* `http_user_agent`

When `ext-plugin-post-resp` fetches an upstream response, it also populates `upstream_addr` and `upstream_response_time` for logging. The response time includes the upstream connection, headers, and body read, but excludes external runner processing and time spent sending the response to the client.

See the [complete list of NGINX variables](https://nginx.org/en/docs/varindex.html) for more information.

## APISIX Variables[​](#apisix-variables "Direct link to APISIX Variables")

In addition to [NGINX variables](https://nginx.org/en/docs/varindex.html), 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](https://docs.api7.ai/apisix/reference/router-options.md#radixtree_uri_with_parameter). 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](https://graphql.org/learn/queries/#operation-name).                                                                                                                                                                                                                                                    |
| `graphql_operation`        | GraphQL [operation type](https://graphql.org/learn/queries/#operation-name).                                                                                                                                                                                                                                                    |
| `graphql_root_fields`      | GraphQL [root fields](https://graphql.org/learn/execution/#root-fields-resolvers).                                                                                                                                                                                                                                              |
| `rate_limiting_info`       | JSON rate-limiting evaluation result. Empty before a supported rate-limiting plugin runs. See [Rate Limiting Information](https://docs.api7.ai/hub/limit-count-rate-limiting-info.md).                                                                                                                                          |
| `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.                                                                                                                                                                                                                                                                                                             |
| `request_type`             | Request category used by observability plugins, such as `traditional_http`, `ai_chat`, or `ai_stream`. A successful WebSocket upgrade is classified as `websocket`.                                                                                                                                                             |
| `mqtt_client_id`           | Client ID in MQTT protocol.                                                                                                                                                                                                                                                                                                     |
| `redis_cmd_line`           | Redis command.                                                                                                                                                                                                                                                                                                                  |
| `rpc_time`                 | RPC request round-trip time.                                                                                                                                                                                                                                                                                                    |

## Custom Variables[​](#custom-variables "Direct link to 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[​](#example "Direct link to Example")

The following examples demonstrate three ways to register custom variables. The first two register `a6_route_labels` and add route labels to a remote log. The third uses `_meta.pre_function` to register a path parameter and rewrite a URI.

#### Create a Service[​](#create-a-service "Direct link to Create a Service")

The following request creates a service with the `http-logger` plugin and an 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[​](#register-a-custom-variable "Direct link to Register a Custom Variable")

You can register custom variables in a startup hook, in a serverless function plugin, or in a plugin's `_meta.pre_function`. The following methods demonstrate each approach.

##### Method 1: At Startup with a Custom Lua Module[​](#method-1-at-startup-with-a-custom-lua-module "Direct link to Method 1: At Startup with a Custom Lua Module")

The following example demonstrates how to register a custom variable at startup. Save the module as `/opt/apisix-custom/custom_variables.lua`. The `a6_route_labels` variable returns the matched route's `labels` value when available:

```
require "apisix"

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)



return true
```

APISIX loads the hook before its main module during initialization, so the hook requires `apisix` before `apisix.core`.

Configure APISIX to find and load the module at startup:

config.yaml

```
apisix:

  extra_lua_path: "/opt/apisix-custom/?.lua"

  lua_module_hook: custom_variables
```

`extra_lua_path` adds the directory to the Lua module search path. `lua_module_hook` explicitly loads `custom_variables` during APISIX initialization. [Reload APISIX](https://docs.api7.ai/apisix/reference/apisix-cli.md#apisix-reload) after changing the module or configuration. The Admin API plugin-reload operation does not reload this startup hook.

For more information, see [create Lua plugin guide](https://docs.api7.ai/apisix/how-to-guide/custom-plugins/create-plugin-in-lua.md).

##### Method 2: In the `serverless` Plugins[​](#method-2-in-the-serverless-plugins "Direct link to 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](https://docs.api7.ai/hub/serverless-functions.md). These plugins run serverless functions before or after a specified [execution phase](https://docs.api7.ai/apisix/key-concepts/plugins.md#plugins-execution-lifecycle), and you can register custom variables in these functions.

The following request adds the `serverless-pre-function` plugin to the previously created service. 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[​](#method-3-in-_metapre_function-of-plugins "Direct link to method-3-in-_metapre_function-of-plugins")

You can use `_meta.pre_function` to run custom code before a plugin executes in each [phase](https://docs.api7.ai/apisix/key-concepts/plugins.md#plugins-execution-lifecycle).

The following example demonstrates how to configure `_meta.pre_function` in [`proxy-rewrite`](https://docs.api7.ai/hub/proxy-rewrite.md), register the request path's `user_id` parameter as a variable, and use the variable in the rewritten path.

To use parameters in the route URI, first set the router to `radixtree_uri_with_parameter` in the [configuration file](https://docs.api7.ai/apisix/reference/configuration-files.md#configyaml-and-configyamlexample):

config.yaml

```
apisix:

  router:

    http: radixtree_uri_with_parameter
```

Then [reload APISIX](https://docs.api7.ai/apisix/reference/apisix-cli.md#apisix-reload) 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"
```

The response should contain the rewritten URL with the value of `user_id`:

```
{

  "url": "http://127.0.0.1/anything/johndoe/world"

}
```

#### Configure Log Format[​](#configure-log-format "Direct link to Configure Log Format")

Create a [plugin metadata](https://docs.api7.ai/apisix/key-concepts/plugin-metadata.md) 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](#nginx-variables).

❷ `a6_route_labels`: custom variable.

#### Create a Route in Service[​](#create-a-route-in-service "Direct link to Create a Route in Service")

Create a [route](https://docs.api7.ai/apisix/key-concepts/routes.md) 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[​](#verify-custom-variable-registration "Direct link to 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[​](#evaluation-order "Direct link to Evaluation Order")

APISIX evaluates variables in the given order:

1. Custom Variables
2. APISIX Variables
3. 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[​](#variable-syntax "Direct link to 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[​](#simple-and-braced-forms "Direct link to 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_host` and `${http_host}`
* `$arg_username-$arg_userid` and `${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 `??`[​](#default-values-with- "Direct link to 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.           |
