Conditional expressions for plugins

Uses: Kong Gateway

Plugin conditions let you 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.

Conditions use Common Expression Language (CEL), a lightweight expression language.

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 all 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.

Condition expressions have a maximum length of 1024 characters.

Condition expressions reference

A condition expression is a string value assigned to the condition field of a plugin object. It follows the syntax, available fields, and types described in CEL expressions for plugins.

Handling default values

default() makes condition expressions safe at runtime. If the expression raises an evaluation error (for example, accessing a missing key in a map), default() returns the fallback value instead of causing a 500 error.

default() must wrap the entire expression. It can’t appear inline within a larger expression:

# Valid — wraps the entire expression
default(kong.ctx.shared.my_flag == "enabled", false)

# Not valid — default() can't be used inline
kong.ctx.shared.my_flag == "enabled" && default(principal.id == "abc", false)

Use default() when your expression references fields that might not be set for every request, such as kong.ctx.shared.* or principal.metadata.*:

default(principal.metadata["Department"] == "finance", false)

Debugging

When Kong Gateway is running with debug logging enabled, a log line is emitted for each condition evaluation.

When a condition is not matched and the plugin is skipped:

plugin condition not matched for plugin 'request-termination' (ID: 66a1adbb-0179-49af-a065-4d0bc6c28cd6): skipped

When a condition is matched and the plugin executes:

plugin condition matched for plugin 'request-termination' (ID: 66a1adbb-0179-49af-a065-4d0bc6c28cd6)

If a condition expression fails at runtime, the error is logged at the ERROR level and Kong Gateway returns a 500 to the client:

error evaluating plugin condition for plugin 'request-termination' (ID: 66a1adbb-0179-49af-a065-4d0bc6c28cd6): No such key: foo

To prevent runtime errors, wrap your expression in default():

"condition": "default(kong.ctx.shared.my_flag == \"enabled\", false)"

Migration from 3.14 to 3.15

The plugin expression language changed between 3.14 and 3.15. In Kong Gateway 3.14, the feature was in beta and used ATC (Abstract Tree Classifier) syntax for plugin conditions. Kong Gateway 3.15 uses CEL (Common Expression Language), which isn’t backwards-compatible.

Any conditional expression that worked in 3.14 will need to be rewritten for 3.15. The main syntax changes are:

  • Prefix matching: ^=startsWith(). For example, http.path ^= "/api" becomes http.path.startsWith("/api").
  • Suffix matching: =^endsWith(). For example, http.path =^ ".json" becomes http.path.endsWith(".json").
  • Regex matching: ~matches(). For example, http.path ~ r#"^/api/v[0-9]+"# becomes http.path.matches("^/api/v[0-9]+").
  • The http.path.segments.<index> fields are replaced by http.path_segments (a list).
  • Header and query fields now return null when absent (instead of an empty string), so null checks may be needed.

For the 3.14 beta reference, see Conditional expressions for plugins in 3.14.

FAQs

Yes, conditions can be used on 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 conditions, since Route expressions are more performant than plugin conditions. This is because:

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

No, the condition expression language doesn’t support this explicitly. As an alternative, you can use a plugin such as Datakit or Pre-Function to parse the body, extract the required value, and store it in kong.ctx.shared. The plugin condition can then reference that kong.ctx.shared key.

If a condition expression fails at runtime, Kong Gateway logs the error at the ERROR level and returns a 500 status code to the client. To prevent this, wrap your expression in a default() call: default(<expression>, false). This returns false (and skips the plugin) instead of a 500 if the expression errors.

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!