Document updated on Sep 10, 2025
Conditional Routing
The Conditional Routing feature enables dynamic backend or multi-backend selection based on request headers (including propagated JWT claims) or custom policy expressions. This functionality enhances flexibility and operational control for complex routing scenarios, including AI/LLM integrations, feature flags, and multi-tenant APIs, among others, without requiring the use of Security Policies or raising errors in the log.
The functionality checks if a specific rule is met before executing a backend, and if it is not, it is skipped from the list. The rules can have any nature, whether they are mutually exclusive within the backend set or complementary to each other. In addition, you can define a special type of fallback backend that evaluates only when ALL rules fail.
The Conditional Routing plays well with the Sequential Proxy and the Workflows, so you can evaluate the response of a previous request and decide whether to execute a backend or not. You can also add backends that do not use Conditional Routing and are always executed.
Configuration of the Conditional Routing
To set a backend
as conditional, you must include in its extra_config
the namespace backend/conditional
with the rules that will allow reaching its destination. Here’s a very simple example:
{
"url_pattern": "/AB-option/1",
"extra_config": {
"backend/conditional": {
"strategy": "policy",
"value": "req_headers.containsCookie('ab-test-xyz', '1')"
}
}
}
In the configuration above, when the request reaches the backend and contains a Cookie AB-TEST-XYZ: 1
, it will be directed to /AB-option/1
. If the condition is not met, then this backend is not executed, and the flow continues (you would probably want an alternative condition or a fallback behavior). Notice that the example above would require input_headers: ["Cookie"]
in the endpoint so the backend has access to the Cookie values.
The configuration options are:
Fields of Conditional Routing
name
string- Only used with the
header
strategy. It is the name of the header you want to use for the evaluation in the canonical format of the MIME header. Make sure to declare the header in theinput_headers
list of the endpoint.Example:"X-Test"
strategy
*- Choose
header
when you want to check the value of a specific header,policy
when you want to write a more complex logical expression, orfallback
when the backend will execute when all the rest of conditional backends have failed to evaluate to true. Only one fallback can be defined per endpoint.Possible values are:"header"
,"policy"
,"fallback"
value
string- The value according to the strategy. With the
header
strategy, this is the literal value contained in the header (case sensitive). With thepolicy
strategy, the Security Policy expression. When using policies you can access to the variablesreq
andreq_params
(a previous backend response might be in the latter), and to advanced macros. Access to headers require you to add the correspondinginput_headers
in the endpoint.Examples:"TestA"
,"hasHeader('X-Test') && req_params.Resp0_message == '0 items left'"
See the different use cases below for more examples.
- Keep policies simple and test them thoroughly before production use to avoid unexpected 500 errors.
- Remember to use the
fallback
to provide default handling or graceful degradation when no conditions match. - Use
input_headers
to enable headers relevant for Conditional Routing to reduce attack surface and increase performance.
Conditional Routing based on JWT claims
If you want the Conditional Routing to access JWT tokens, make sure to propagate claims as headers and add them to the input_headers
list of the endpoint.
Once this is done, you can access the claim values using their propagated header names.
Fallback backend, no-routing, and non-conditionals
Depending on the configuration rules you use, when you don’t use a fallback
conditional, it might happen that none of the backends are suitable to retrieve their content. In that case, the endpoint would return a 500
error as there is no possible response.
Use the fallback
strategy to define a backend when none of the other rules have worked, being your go-to solution for impossible evaluations.
In addition, if you add backends that do not have any Conditional Routing, they are always executed (unless you add other policies preventing it). If you mix non-conditional with conditional routing, the fallback
strategy applies when the conditionals evaluate all to false
, and the non-conditionals are not taken into account.
No-op considerations
The Conditional Routing allows you to use no-op
if needed and add multiple backends. You need to ensure that only one backend returns its content and that its encoding is no-op
.
When using the Sequential Proxy + Conditional Routing + no-op
, it’s essential to comprehend that you cannot access individual fields of previous responses (e.g., req_params.Resp0_xxx
). This is because the params contain the whole body and not the decoded response (which is exactly what no-op does).
AB Testing and Feature Flags using Conditional Routing
The AB testing and Feature Flags enablement is one of the many possible use cases. You can use information in a request, like setting a header for the AB Test, a Cookie, or choosing a route based on who the user is (JWT) or even the current time.
Whether it’s AB testing or Feature Flags, you might have server-side functionality that flags a user (e.g., introducing a variant as a JWT claim), or client-side functionality like an SDK that sets a header for a specific variant. In any of the cases, you can use a rule to send users to a different backend, or treat the same backend differently (e.g., use the same backend but change the logging behavior)
Here’s a simple configuration for an AB test that reads the content of the X-AB-TEST
headers to route:
{
"endpoint": "/AB-TESTING",
"input_headers": [
"X-Ab-Test"
],
"backend": [
{
"url_pattern": "/AB-option/A",
"extra_config": {
"backend/conditional": {
"strategy": "header",
"name": "X-Ab-Test",
"value": "A"
}
}
},
{
"url_pattern": "/AB-option/B",
"extra_config": {
"backend/conditional": {
"strategy": "header",
"name": "X-Ab-Test",
"value": "B"
}
}
},
{
"url_pattern": "/default",
"extra_config": {
"backend/conditional": {
"strategy": "fallback"
}
}
}
]
}
Notice that this approach is similar to the one offered by the Dynamic Routing but Dynamic does not offer the fallback option:
{
"@comment": "Dynamic routing alternative with no fallback possible",
"host": ["http://host.example.com"],
"url_pattern": "/AB-option/{input_headers.X-Ab-Test}",
"disable_host_sanitize": true
}
In the case above, you would need an additional Security Policy to avoid errors when the header is not present.
AI/LLM Routing
The conditional backend is particularly vital for scalable AI/LLM service orchestration and complex multi-backend routing where simple static backend assignments are insufficient. It integrates safely and predictably within KrakenD’s existing configuration schema and operational model.
For example, routing requests based on an X-Test header value allows targeting different AI model versions, while a policy checking hasHeader(‘X-Engine’) can gate experimental logic, complemented by fallback logic for any unmatched requests.
Geographic Routing
Distribute requests to groups of backends based on request attributes like geographic headers or custom expressions. For instance, by enabling the GeoIP plugin, you can change the backend datacenter depending on the origin of the request.
{
"endpoint": "/foo",
"backend": [
{
"url_pattern": "/bar",
"host":["europe.example.com"],
"extra_config": {
"backend/conditional": {
"strategy": "policy",
"value": "geoIP().RepresentedCountry.IsInEuropeanUnion"
}
}
},
{
"url_pattern": "/bar",
"host":["us.example.com"],
"extra_config": {
"backend/conditional": {
"strategy": "fallback"
}
}
}
]
}
Another useful policy in this example could be geoIP().Country.IsoCode in ["US","UK","AU"]
Differences with similar functionality
A Security Policy or a CEL expression can abort the execution of an endpoint or the backend, and they allow you to set custom policies to do so. These two components have the mission to protect content from a security point of view. When the rule is met, the execution raises an error and stops.
On the other side, the Conditional Routing treats it as a “normal behavior” when a condition is not met and the backend is skipped, without raising an error in the other functionality. The Conditional Routing assimilates the rule into the regular flow of your application, not as an exception.
Another close functionality is the Dynamic Routing, which dynamically defines the host or URL. Still, here you choose a completely different set of backend definitions according to rules, not values.