CEL reference overview
Common Expression Language (CEL) is a fast, safe expression language used throughout Agentgateway to evaluate user-defined expressions against live request data. CEL expressions are evaluated at request time against a rich context of variables describing the request, response, authentication state, and more. CEL is not as general-purpose as Lua or WASM, but it is significantly faster and sufficient for the majority of gateway policy use cases.Where CEL is used
Agentgateway uses CEL in several places across the request processing pipeline:- Authorization rules — define which requests are allowed or denied
- Rate limiting conditions — select the attribute to rate limit on (for example, per user or per API key)
- Logs and traces — define which request attributes to include as structured fields
- Header and body transformations — compute new header or body values
- MCP authorization — control which MCP tools, prompts, and resources a caller can access
Expression syntax
CEL expressions are single-line expressions that evaluate to a value. They support:| Syntax | Description | Example |
|---|---|---|
| Field access | Dot notation | request.method |
| Map lookup | Bracket notation | request.headers["x-api-key"] |
| Comparison | ==, !=, <, <=, >, >= | response.code >= 500 |
| Logical | &&, ||, ! | jwt.role == "admin" && request.method == "GET" |
| Membership | in | mcp.tool.name in ["read_file", "list_files"] |
| String methods | Built-in string functions | request.path.startsWith("/api") |
| Ternary | condition ? a : b | has(jwt.sub) ? jwt.sub : "anonymous" |
| Field existence | has() | has(jwt.sub) |
Available context objects
Agentgateway exposes the following top-level objects to CEL expressions. Not all objects are available in all contexts — for example,response is not available during a request-phase transformation, and mcp is only present for MCP requests.
| Object | Description |
|---|---|
request | Attributes of the incoming HTTP request (method, path, headers, body, timing) |
response | Attributes of the HTTP response (status code, headers, body) |
source | Attributes of the downstream connection (IP, port, mTLS identity) |
env | Selected Kubernetes environment attributes (pod name, namespace, gateway) |
jwt | Claims from a verified JWT token (present only when JWT auth is enabled) |
apiKey | Claims from a verified API key (present only when API key auth is enabled) |
basicAuth | Basic authentication credentials (present only when basic auth is enabled) |
mcp | MCP-specific context: the tool, prompt, or resource being accessed |
llm | LLM-specific context: model, token counts, prompt, completion, parameters |
llmRequest | Raw LLM request before processing (available only during LLM policy evaluation) |
backend | Information about the selected backend (name, type, protocol) |
extauthz | Dynamic metadata from external authorization filters |
extproc | Dynamic metadata from external processing filters |
metadata | Values set by transformation metadata expressions |
Agentgateway uses static analysis at configuration load time to determine which context fields your expressions reference. Fields that are not referenced are not collected, so you only pay for what you use. This is especially important for
request.body and response.body, which require buffering.Practical examples
Custom CEL functions
Agentgateway extends CEL with custom functions beyond the standard library.JSON and encoding
JSON and encoding
| Function | Description | Example |
|---|---|---|
json | Parse a string or bytes as JSON | json(request.body).some_field |
toJson | Convert a CEL value to a JSON string | toJson({"hello": "world"}) |
base64.encode | Encode a string to base64 | base64.encode("hello") |
base64.decode | Decode a base64 string to bytes | string(base64.decode("aGVsbG8K")) |
JWT and authentication
JWT and authentication
| Function | Description | Example |
|---|---|---|
unvalidatedJwtPayload | Parse a JWT payload without verifying the signature | unvalidatedJwtPayload(request.headers.authorization.split(" ")[1]).sub |
Control flow and variables
Control flow and variables
| Function | Description | Example |
|---|---|---|
with | Bind an expression result to a variable (CEL has no native bindings) | json(request.body).with(b, b.field_a + b.field_b) |
variables | Expose all context variables as a single value | variables |
default | Return a fallback if the expression fails to resolve | default(request.headers["missing-header"], "fallback") |
coalesce | Return the first non-null, non-error expression | coalesce(request.headers["x-id"], json(request.body).id, "fallback") |
fail | Unconditionally fail an expression | fail |
Map and collection utilities
Map and collection utilities
| Function | Description | Example |
|---|---|---|
mapValues | Apply a function to all values in a map | — |
filterKeys | Return a new map keeping only keys matching a predicate | {"a":1,"b":2}.filterKeys(k, k == "a") |
merge | Join two maps (right-hand values win on key conflict) | {"a":2,"k":"v"}.merge({"a":3}) |
flatten | Flatten a list or struct into many fields (logging/tracing only) | flatten(request.headers) |
flattenRecursive | Like flatten but flattens multiple levels (logging/tracing only) | — |
String and regex
String and regex
| Function | Description | Example |
|---|---|---|
regexReplace | Replace substrings matching a regular expression | "/id/1234/data".regexReplace("/id/[0-9]*/", "/id/{id}/") |
random | Generate a random float from 0.0 to 1.0 | random() < 0.1 |
uuid | Generate a random UUIDv4 | uuid() |
Standard library highlights
Standard library highlights
All standard CEL functions are available, including collections (
contains, size, has, map, filter, all, exists), type conversion (string, bytes, double, int, uint), strings (startsWith, endsWith, matches, trim, replace, split, substring), time functions (duration, timestamp, getFullYear, getMonth), and IP/CIDR helpers (isIP, ip, cidr).Header views
Therequest.headers and response.headers objects expose chainable methods for common header access patterns:
| Method | Description | Example |
|---|---|---|
| Direct access | Returns a string for single values, list for multiple | request.headers["content-type"] |
.redacted() | Replace sensitive values with "<redacted>" | request.headers.redacted().authorization |
.join() | Join all entries for a header with , | request.headers.join()["x-forwarded-for"] |
.raw() | Return raw entries as a list | request.headers.raw()["set-cookie"] |
.split() | Split entries on , and return as a list | request.headers.split()["accept"] |
.cookie(name) | Parse the Cookie header and return a named cookie value | request.headers.cookie("session") |
Query string access
request.pathAndQuery and request.uri expose query-aware methods:
| Method | Description | Example |
|---|---|---|
.query(name) | Return all values for a query parameter as a list | request.pathAndQuery.query("foo") == ["bar"] |
.addQuery(name, value) | Return a new string with the parameter appended | request.pathAndQuery.addQuery("foo", "qux") |
.setQuery(name, value) | Return a new string with the parameter replaced | request.uri.setQuery("foo", "qux") |
Reference pages
Request context
Full reference for
request, response, source, env, jwt, apiKey, basicAuth, backend, and metadata objects.MCP context
Full reference for the
mcp object: tools, prompts, and resources.LLM context
Full reference for the
llm object: model, token counts, prompt, completion, and parameters.