Conditional expressions for plugins

Beta and uses: Kong Gateway
Related Documentation
Minimum Version
Kong Gateway - 3.14

Plugin conditions allow you to attach an optional condition expression to any plugin. When a request comes in, Kong Gateway evaluates the expression immediately before the plugin’s access phase. If the expression evaluates to true, the plugin runs normally. If it evaluates to false, the plugin is skipped for that request.

Here are some common use cases for setting a condition on a plugin:

  • Skip a global plugin for specific Routes, hosts, or request paths without removing the plugin or duplicating it across individual Routes.
  • Enforce a plugin only for specific HTTP methods, headers, or query parameters.
  • Make one plugin’s execution depend on context set by a higher-priority plugin.
  • Condition plugin behavior on the authenticated Consumer, matched Route, or target Gateway Service.

How it works

When Kong Gateway receives a request, it matches the request to a Route and determines which plugins are in scope according to the plugin scoping rules. For each in-scope plugin that has a condition set, Kong Gateway evaluates the expression before that plugin’s access phase runs.

The following plugin contexts always execute, regardless of the condition: init_worker, configure, certificate, and rewrite. If the condition evaluates to false, the plugin’s access phase and later phases are skipped. Because of this, values set during or after the response phase (for example, kong.ctx.shared values written in header_filter or body_filter) aren’t available to condition expressions.

Unlike plugin scopes, which are evaluated once at router time before any plugins run, conditions are evaluated per request, per plugin, immediately before each plugin executes. This means a higher-priority plugin can set values in kong.ctx.shared that a lower-priority plugin’s condition can then read.

If no condition is set, the plugin always executes.

Performance considerations

Plugin scopes are evaluated once at router time and are more efficient than conditions, which are evaluated per-request for each conditioned plugin. Where possible, use plugin scopes to control plugin execution rather than conditions.

When conditions are necessary, keep the following in mind:

  • A plugin’s configuration is always loaded into memory, even if its condition evaluates to false.
  • Complex compound expressions with many fields are more expensive to evaluate than simple single-field expressions.
  • Conditions that reference kong.ctx.shared fields require a higher-priority plugin to set those values on every request, which adds its own overhead.

Limitations

Plugin conditions are only supported in the HTTP subsystem. They can’t be used with stream (TCP, TLS, UDP) Routes.

The following plugins do not support conditions:

  • Pre-Function
  • Post-Function
  • WebSocket Size Limit
  • WebSocket Validator

All other Kong Gateway plugins support conditions.

Plugin conditions reference

This reference describes the expression syntax and available fields for plugin conditions.

Expression formatting

A condition expression is a string value assigned to the condition field of a plugin object. It follows the same ATC (Abstract Tree Classifier) expression syntax used by Kong Gateway’s expressions router.

A predicate is the basic unit of an expression and takes the following form:

http.method == "GET"

This predicate has the following structure:

  • http.method: Field
  • ==: Operator
  • "GET": Constant value

Predicates are made up of smaller units that you can configure:

Object

Description

Example

Field A value extracted from the current request or Kong Gateway context. An absent field value always causes the predicate to evaluate to false. The field always appears on the left side of the predicate. http.method
Constant value The value that the field is compared against. Always appears on the right side of the predicate. "GET"
Operator Defines the comparison to perform between the field and the constant value. Always appears between the field and the constant value. ==
Predicate Compares a field against a constant value using the given operator. Returns true if the comparison passes, false if it does not. http.method == "GET"

Field and constant value types

Types define what you can use for a predicate’s field and constant value. Expressions language is strongly typed. Operations are only performed if such an operation makes sense in regard to the actual type of field and constant.

Type conversion at runtime is not supported, either explicitly or implicitly. Types are always known at the time a route is parsed. An error is returned if the operator cannot be performed on the provided field and constant.

The expressions language currently supports the following types:

Object Description Field type Constant type
String A string value, always in valid UTF-8. They can be defined with string literal that looks like "content". You can also use the following escape sequences:
  • \n: Newline character
  • \r: Carriage return character
  • \t: Horizontal tab character
  • \\: The \ character
  • \": The " character
Supported Supported
IpCidr Range of IP addresses in CIDR format. Can be either IPv4 (net.src.ip in 192.168.1.0/24) or IPv6 (net.src.ip in fd00::/8). The expressions parser rejects any CIDR literal where the host portion contains any non-zero bits. This means that 192.168.0.1/24 won’t pass the parser check because the intention of the author is unclear. Not supported Supported
IpAddr A single IP address in IPv4 Dot-decimal notation (net.src.ip == 192.168.1.1), or the standard IPv6 Address Format (net.src.ip == fd00::1). Can be either IPv4 or IPv6. Supported Supported
Int A 64-bit signed integer. There is only one integer type in expressions. All integers are signed 64-bit integers. Integer literals can be written as 12345, -12345, or in hexadecimal format, such as 0xab12ff, or in octet format like 0751. Supported Supported
Regex Regex are written as String literals, but they are parsed when the ~ regex operator is present and checked for validity according to the Rust regex crate syntax. For example, in the following predicate, the constant is parsed as a regex: http.path ~ r#"/foo/bar/.+"# Not supported Supported

In addition, the expressions router also supports one composite type, Array. Array types are written as Type[]. For example: String[], Int[]. Currently, arrays can only be present in field values. They are used in case one field could contain multiple values. For example, http.headers.x or http.queries.x.

Available fields

Plugin conditions support all standard HTTP fields from the expressions router, plus additional context fields that are only available during plugin execution.

HTTP request fields

These fields reflect the state of the incoming HTTP request at the time the condition is evaluated. These values may have been modified by higher-priority plugins before the condition is evaluated (for example, a plugin that rewrites a header or query parameter).

Field

Type

Description

http.method String The HTTP method of the incoming request, for example "GET" or "POST".
http.host String The Host header of the incoming request.
http.path String The normalized request path. Does not include query parameters.
http.path.segments.<index> String A single path segment extracted from the normalized path, using a zero-based index. For example, for /a/b/c, http.path.segments.1 returns "b".
http.path.segments.<index>_<index> String A range of path segments joined by /. For example, for /a/b/c, http.path.segments.0_1 returns "a/b".
http.path.segments.len Int The number of segments in the normalized path. For example, /a/b/c returns 3.
http.headers.<header_name> String[] The value(s) of the specified request header. Header names are always normalized to lowercase with underscores, so X-My-Header becomes http.headers.x_my_header.
http.queries.<param_name> String[] The value(s) of the specified query parameter.
net.src.ip IpAddr The IP address of the client.
net.src.port Int The port used by the client to connect.
net.dst.ip IpAddr The listening IP address where Kong Gateway accepted the connection.
net.dst.port Int The listening port where Kong Gateway accepted the connection.

Hyphens (-) in header names must be replaced with underscores (_) in ATC expressions. For example, x-my-header becomes http.headers.x_my_header.

Plugin condition-specific fields

The following fields are populated during plugin execution and reflect the Gateway context at the time the condition is evaluated.

Field

Type

Description

consumer.id String The UUID of the authenticated consumer, if one has been identified by an earlier plugin.
consumer.username String The username of the authenticated consumer.
consumer.custom_id String The custom ID of the authenticated consumer.
route.id String The UUID of the matched route.
route.name String The name of the matched route.
service.id String The UUID of the target service.
service.name String The name of the target service.
kong.ctx.shared.KEY_NAME String A value from the kong.ctx.shared table, set by a higher-priority plugin earlier in the same request.

Notes:

  • consumer.* fields are only populated after an authentication plugin (such as Key Auth or Basic Auth) has run. Conditions referencing consumer fields must be on a plugin with a lower priority than the authentication plugin.
  • kong.ctx.shared.KEY_NAME fields are only populated if a higher-priority plugin has set them during the access phase. Values set during the response phase are not available.

Operators

An operator defines the desired comparison action to be performed on the field against the provided constant value. The operator always displays in the middle of the predicate, between the field and constant value.

The expressions language supports a rich set of operators that can be performed on various data types.

Operator

Name

Description

== Equals Field value is equal to the constant value.
!= Not equals Field value does not equal the constant value.
~ Regex match Field value matches regex.
^= Prefix match Field value starts with the constant value.
=^ Postfix match Field value ends with the constant value.
>= Greater than or equal Field value is greater than or equal to the constant value.
> Greater than Field value is greater than the constant value.
<= Less than or equal Field value is less than or equal to the constant value.
< Less than Field value is less than the constant value.
in In Field value is inside the constant value. This operator is used with IpAddr and IpCidr types to perform an efficient IP list check.

For example, net.src.ip in 192.168.0.0/24 only returns true if the value of net.src.ip is within 192.168.0.0/24.
not in Not in Field value is not inside the constant value. This operator is used with IpAddr and IpCidr types to perform an efficient IP list check.

For example, net.src.ip in 192.168.0.0/24 only returns true if the value of net.src.ip is within 192.168.0.0/24.
contains Contains Field value contains the constant value. This operator is used to check the existence of a string inside another string.

For example, http.header contains \"foo\" returns true if foo can be found anywhere inside http.header. This will match an HTTP.header that looks like x-foo, x-abc-foo, or x-fooy, for example.
&& And Returns true if both expressions on the left and right sides evaluate to true.
|| Or Returns true if any expressions on the left or right side evaluate to true.
(Expression) Parenthesis Groups expressions together to be evaluated first.
! Not Negates the result of a parenthesized expression.

The ! operator can only be used with parenthesized expression like !(foo == 1), it cannot be used with a bare predicate like ! foo == 1.”

Allowed type and operator combinations

Depending on the field type, only certain content types and operators are supported.

Field type

Supported content types and their supported operators

String
  • String: ==, !=, ~, ^=, =^, contains
  • Regex: ~
IpAddr
  • IpCidr: in, not in
  • IpAddr: ==
Int
  • Int: ==, !=, >=, >, <=, <
Expression
  • Regex: &&, ||

The ~ regex operator does not automatically anchor to the start of the string. http.path ~ r#"/foo/\d"# would match /foo/1 and /other/foo/1. To anchor from the start, use the ^ character: http.path ~ r#"^/foo/\d"#.

Example expressions

The following tables contain examples of different types of expressions.

HTTP request fields

The following expressions can be used to match HTTP requests.

Name

Example

Description

Match by HTTP method http.method == "POST" Matches requests using the POST method.
Match by path prefix http.path ^= "/api/v2" Matches requests with paths starting with /api/v2.
Match by regex path http.path ~ r#"^/api/v[0-9]+"# Matches versioned API paths such as /api/v1 or /api/v2.
Match by host http.host == "internal.example.com" Matches requests sent to a specific host.
Match by header value http.headers.x_version == "2" Matches requests with the header x-version: 2.
Match by header prefix http.headers.authorization ^= "Bearer" Matches requests with a Bearer token in the Authorization header.
Match by query parameter http.queries.auth == "required" Matches requests with the query parameter auth=required.
Exclude a path prefix !(http.path ^= "/health") Skips the plugin for any path starting with /health.
Compound: method and header http.method == "POST" && http.headers.x_version == "2" Matches only POST requests that also include the x-version: 2 header.
Compound: method or path http.method == "DELETE" || http.path ^= "/admin" Matches DELETE requests or any request to an /admin path.

Consumer fields

The following expressions can be used to match Consumer metadata.

Name

Example

Description

Match by Consumer username consumer.username == "alice" Matches requests authenticated as the Consumer alice.
Match by Consumer UUID consumer.id == "a1b2c3d4-..." Matches requests from a specific Consumer by UUID.
Match by Consumer custom ID consumer.custom_id == "ext-user-123" Matches requests from a Consumer with a specific external identifier.

Route and Service fields

The following expressions can be used to match Route and Service metadata.

Name

Example

Description

Match by Route name route.name == "payments-route" Matches requests routed through a specific Route.
Exclude a Route by name route.name != "health-check-route" Skips the plugin for a specific Route.
Match by Service name service.name == "payments-service" Matches requests targeting a specific Gateway Service.

kong.ctx.shared fields

The following expressions can be used to match kong.ctx.shared fields.

Name

Example

Description

Match on a shared context value kong.ctx.shared.my_flag == "enabled" Matches requests where a higher-priority plugin set kong.ctx.shared.my_flag to "enabled".
Exclude based on shared context !(kong.ctx.shared.bypass == "true") Skips the plugin unless a higher-priority plugin has set the bypass flag.

Debugging

When Kong Gateway is running with debug logging enabled, a log line is emitted for each condition evaluation, showing the plugin name, plugin ID, the expression, and the result:

[kong] plugin_condition.lua:234 plugin condition evaluated for plugin
'request-termination' (ID: 66a1adbb-0179-49af-a065-4d0bc6c28cd6):
expression="http.headers.x_block == "true"", result=false

When result=false, the plugin was skipped for that request. When result=true, the plugin executed normally.

FAQs

Yes, conditions can be used in global plugins that are not scoped to a Route, Service, Consumer, or Consumer Group.

Routes with expression router conditions should be used instead of per-plugin conditionals wherever practical, since Route expressions will be more performant than plugin conditions. This is because:

  • The init phase of plugins on excluded Routes won’t execute.
  • The plugin conditional won’t need to be evaluated.

While the conditional expression language doesn’t support this explicitly, you could use a plugin such as Datakit or Pre-Function to parse the body, extract the value required, and put the value in a variable in the request context. The conditional expression for the plugin can then be set based on that variable.

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!