# Built-In Variables

*Built-in variables* in API7 Gateway are pre-defined variables that can be directly referenced in configurations. They are often used in plugin configurations, route matching, and log customization.

API7 Gateway 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 variables that expose request and response information.

Commonly used variables include:

| Variable          | Description                                                                                                                                                                                                                                                                                                                     |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `upstream_addr`   | IP address and port, or UNIX-domain socket path, of the upstream server.                                                                                                                                                                                                                                                        |
| `remote_addr`     | Client address.                                                                                                                                                                                                                                                                                                                 |
| `request_method`  | Request method, such as `GET` or `POST`.                                                                                                                                                                                                                                                                                        |
| `request_uri`     | Full original request URI, including arguments.                                                                                                                                                                                                                                                                                 |
| `server_name`     | Name of the server that accepted the request.                                                                                                                                                                                                                                                                                   |
| `status`          | Response status. It can be `000` until NGINX establishes the response status. Use it in response-phase contexts, such as [Debug Session sampling rules](https://docs.api7.ai/api7-gateway/observability/debug-sessions.md#step-2-capture-only-the-traffic-you-care-about) or logging plugins; do not use it for route matching. |
| `uri`             | Current normalized request URI, which can change during request processing.                                                                                                                                                                                                                                                     |
| `http_user_agent` | Value of the `User-Agent` request header.                                                                                                                                                                                                                                                                                       |

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.                                                                                                                                                                                                                                          |
| `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.                                                                                                                                                                                                                                              |
| `method`                   | HTTP request method, such as `GET` or `POST`. The equivalent NGINX variable is `request_method`.                                                                                                                                                                                                                                |
| `balancer_ip`              | Upstream server IP.                                                                                                                                                                                                                                                                                                             |
| `balancer_port`            | Upstream server port.                                                                                                                                                                                                                                                                                                           |
| `consumer_name`            | Consumer username.                                                                                                                                                                                                                                                                                                              |
| `consumer_group_id`        | Inherited runtime variable for a consumer group ID. API7 Gateway does not assign consumer group IDs, so this variable is unset.                                                                                                                                                                                                 |
| `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).                                                                                                                                                                                                                                              |
| `route_id`                 | Route ID.                                                                                                                                                                                                                                                                                                                       |
| `route_name`               | Route name.                                                                                                                                                                                                                                                                                                                     |
| `service_id`               | Service ID.                                                                                                                                                                                                                                                                                                                     |
| `service_name`             | Service name.                                                                                                                                                                                                                                                                                                                   |
| `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.                                                                                                                                                                                                                                                                                                    |
| `external_user.*`          | External user information. This variable can be populated by authentication plugins such as `openid-connect`, making it available to other plugins. For example, `limit-count-advanced` can enforce rate limiting by username when `key` is set to `${external_user.preferred_username}`.                                       |
| `upstream_unresolved_host` | The configured upstream host or domain name before DNS resolution (the upstream node's `domain` or `host`). Available in API7 Enterprise from version 3.9.15.                                                                                                                                                                   |
| `rate_limiting_info`       | JSON object that describes how a rate limiting plugin evaluated the request. See Rate Limiting Information below. Available in API7 Enterprise from version 3.9.6.                                                                                                                                                              |

caution

`http_*` reads an HTTP request header. It is not a prefix for other built-in variables. For example, `http_uri`, `http_method`, and `http_status` read request headers named `Uri`, `Method`, and `Status`. Use `uri`, `method`, and `status` for the request path, request method, and response status.

API7 Gateway does not verify that such a header exists when compiling an expression. If a client does not send the header, a condition that expects it to have a value can fail to match without an error.

## Rate Limiting Information[​](#rate-limiting-information "Direct link to Rate Limiting Information")

The `rate_limiting_info` variable holds a JSON object that describes how a rate limiting plugin evaluated the request. Available in API7 Enterprise from version 3.9.6.

The following plugins set the variable: `limit-count`, `limit-count-advanced`, `graphql-limit-count`, and `ai-rate-limiting`. Before one of them runs, or on a route without any of them, the variable is an empty string.

### Add the Variable to the Access Log[​](#add-the-variable-to-the-access-log "Direct link to Add the Variable to the Access Log")

Add the variable to the access log in the data plane's `config.yaml`. With `access_log_format_escape` set to `json`, the variable is written as an escaped JSON string inside the log line:

conf/config.yaml

```
nginx_config:

  http:

    access_log_format: '{"time_local":"$time_local","remote_addr":"$remote_addr","request":"$request","status":"$status","rate_limiting_info":"$rate_limiting_info"}'

    access_log_format_escape: json
```

Parse the log line as JSON first, then parse the value of `rate_limiting_info` as JSON again. Read fields by name: the order of the fields is not guaranteed. You can also reference the variable in the log format of a logger plugin.

A request counted in a fixed window produces a value like the following:

```
{"rate_limiting_key":"/apisix/routes/1:1:127.0.0.1","rate_limiting_limit":10,"rate_limiting_remaining":3,"rate_limiting_reset":42,"window_type":"fixed","window_size_ms":60000,"decision":"allowed","cost":1,"evaluated_at_ms":1759212345678,"current_window":{"start_ms":1759212300123,"end_ms":1759212360123,"count":7,"created":false}}
```

A request counted in a sliding window produces a value like the following:

```
{"rate_limiting_key":"/apisix/routes/1:1:127.0.0.1","rate_limiting_limit":10,"rate_limiting_remaining":3,"rate_limiting_reset":14,"window_type":"sliding","window_size_ms":60000,"decision":"allowed","cost":1,"evaluated_at_ms":1759212345678,"current_window":{"id":29320205,"start_ms":1759212300000,"end_ms":1759212360000,"count":4},"previous_window":{"count":10,"weight":0.2387,"weighted_count":2.387}}
```

### Fields[​](#fields "Direct link to Fields")

The following fields are always present:

| Field                     | Description                                                                                                                                                                                                    |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `rate_limiting_key`       | Counter key that the request was counted under.                                                                                                                                                                |
| `rate_limiting_limit`     | Quota of the window.                                                                                                                                                                                           |
| `rate_limiting_remaining` | Remaining quota after the request. It is `0` when the request is rejected or the counter could not be updated.                                                                                                 |
| `rate_limiting_reset`     | Seconds until the quota resets, rounded down to a whole number. When a sliding window rejects a request, it is the time until a request can be allowed again, which can be earlier than the end of the window. |

The following fields describe the window that the request was counted in. Available in API7 Enterprise from version 3.10.8.

| Field                                                                               | Description                                                                                                                                                                                                                         |
| ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `window_type`                                                                       | `fixed` or `sliding`.                                                                                                                                                                                                               |
| `window_size_ms`                                                                    | `time_window` in milliseconds.                                                                                                                                                                                                      |
| `decision`                                                                          | `allowed`, `rejected`, or `error`. `error` means the counter could not be updated, for example because Redis is unreachable. An `error` value contains only the four fields above, `window_type`, `window_size_ms`, and `decision`. |
| `cost`                                                                              | Amount that the request added to the counter. See Counted Cost below.                                                                                                                                                               |
| `evaluated_at_ms`                                                                   | Time when the request was evaluated.                                                                                                                                                                                                |
| `current_window.start_ms`, `current_window.end_ms`                                  | Boundaries of the current window.                                                                                                                                                                                                   |
| `current_window.count`                                                              | Count of the current window after the request, including its `cost`.                                                                                                                                                                |
| `current_window.created`                                                            | Fixed window only. `true` for the request that started the window.                                                                                                                                                                  |
| `current_window.id`                                                                 | Sliding window only. Number of windows since the Unix epoch.                                                                                                                                                                        |
| `previous_window.count`, `previous_window.weight`, `previous_window.weighted_count` | Sliding window only. Count of the previous window, the weight applied to it, and their product.                                                                                                                                     |
| `delayed_sync`                                                                      | Delayed synchronization only. See Delayed Synchronization below.                                                                                                                                                                    |

All `*_ms` fields are Unix timestamps or durations in milliseconds, taken from the clock of the gateway instance.

A field that does not apply to the window type or the configuration is omitted. A field that applies but is unknown for the request is `null`. For example, `current_window.created` is `null` with the Redis policies, and `current_window.count` is `null` when a fixed window with the `local` policy rejects the request.

### Window Types[​](#window-types "Direct link to Window Types")

A fixed window is not aligned to the clock. It starts with the first request counted under the key and ends `time_window` seconds later. With the Redis policies, the end of the window is derived from the TTL of the Redis counter and can differ by a few milliseconds from one request to another.

A sliding window is aligned to the clock. The current window starts at `current_window.id * window_size_ms`. A request is allowed while the count of the current window, plus the count of the previous window weighted by the share of it still inside the sliding range, stays below the quota. `previous_window.count` is capped at the quota, `previous_window.weight` is that share from 0 to 1, and `previous_window.weighted_count` is their product.

### Counted Cost[​](#counted-cost "Direct link to Counted Cost")

`cost` is what the request added to the counter, and it depends on how the request was counted:

* A fixed window counts the cost even when it rejects the request.
* A sliding window counts only allowed requests, so a rejected request has a `cost` of `0`.
* Delayed synchronization counts only allowed requests, for both window types, so a rejected request has a `cost` of `0`.

`ai-rate-limiting` checks the quota before it forwards a request without counting the request, so that check reports a `cost` of `0`. It counts the tokens after the response.

### Delayed Synchronization[​](#delayed-synchronization "Direct link to Delayed Synchronization")

When a Redis policy is used with `sync_interval`, each gateway instance counts requests locally and synchronizes with the shared counter in Redis once per interval. The `delayed_sync` object describes the snapshot that the request was checked against:

| Field                       | Description                                                                                                |
| --------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `delayed_sync.synced_at_ms` | Time when this gateway instance last synchronized the counter.                                             |
| `delayed_sync.synced_count` | Count of the current window in Redis at that time.                                                         |
| `delayed_sync.local_delta`  | Amount that this gateway instance counted since then and has not synchronized yet, excluding this request. |

The counts and the weight are a snapshot as of `synced_at_ms`:

* `current_window.count` is an estimate, `synced_count + local_delta + cost`. It does not include what other gateway instances counted since their last synchronization.
* For a sliding window, `current_window` and `previous_window` describe the windows at the time of the last synchronization. `previous_window.weight` is the weight fixed at synchronization time, which is the weight used for this request, not the weight at `evaluated_at_ms`.
* Each synchronization replaces the snapshot. A request that arrives shortly after the window boundary can still be checked against the snapshot of the previous window, so its `evaluated_at_ms` can be later than `current_window.end_ms`.

### Multiple Rules and Plugins[​](#multiple-rules-and-plugins "Direct link to Multiple Rules and Plugins")

The variable holds one evaluation. Each evaluation replaces the previous value, so the variable describes the last rule that was evaluated:

* When a plugin is configured with multiple `rules`, the rules are evaluated in order and evaluation stops at the first rule that rejects the request. The variable describes that rule, or the last rule if no rule rejected the request.
* When more than one of the plugins above runs on a request, the variable describes the rule that the last plugin evaluated.

## Evaluation Order[​](#evaluation-order "Direct link to Evaluation Order")

API7 Gateway evaluates variables in the given order:

1. Custom Variables
2. APISIX Variables
3. NGINX Variables

If a variable is successfully sourced in custom variables, API7 Gateway 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.           |
