Route delegation
Verified Code examples on this page have been automatically tested and verified.
Delegate routing decisions to route groups for independent team management.
Delegate routing decisions from a parent route to a set of child routes defined in a route group. Route delegation lets you break up large routing configurations into smaller, independently managed pieces.
About
As your gateway manages traffic for more routes, managing all routing rules in a single configuration becomes difficult. Route delegation lets you split routing configurations so that different teams can own their routes independently.
In standalone mode, route delegation uses route groups. A parent route references a route group as its backend, and the route group contains child routes that handle more specific paths within the parent’s prefix.
| Element | Description |
|---|---|
| Parent route | A route defined on a listener. Instead of routing directly to a backend, it references a routeGroup in its backends list. The parent must use a pathPrefix matcher. |
| Route group | Defined at the top level under routeGroups. Contains a name and a list of child routes. |
| Child route | A route inside a route group. Uses the same matching logic as regular routes (path, headers, query parameters). The child’s path must fall within the parent’s prefix to be reachable. |
Example request flow
Request: /anything/team1/foo
|
v
Parent Route (matches /anything/team1)
|
| delegates to routeGroup: team1-routes
v
Route Group "team1-routes"
|
| selects best matching child route
v
Child Route "child-foo" (matches /anything/team1/foo)
|
v
Backend: team1-foo.example.com:8080
More details
Review more details about how route delegation works in standalone mode.
| Area | Description |
|---|---|
| Parent path matcher | A parent route that delegates to a route group must use a pathPrefix matcher. |
| Child path scope | Child routes must match a path that falls within the parent’s prefix. For example, if the parent matches /api, a child must match a path starting with /api. |
| Cyclic delegation | Agentgateway does not allow cyclic delegation. If route group A delegates to B, and B delegates back to A, agentgateway detects the cycle at runtime and returns a 500 response. See Error responses. |
| Missing route group | If a route references a routeGroup that does not exist, agentgateway returns a 404 response for that route, the same as a path with no match. See Error responses. |
Before you begin
Install the agentgateway binary.
Basic delegation
Delegate traffic from a parent route to a route group with two child routes.
In this example, a parent route matches the /anything/team1 prefix and delegates to a route group
called team1-routes. The route group contains two child routes: child-foo matches
/anything/team1/foo and child-bar matches /anything/team1/bar.
-
Create the configuration file.
cat > config.yaml <<'EOF'# yaml-language-server: $schema=https://agentgateway.dev/schema/configgateways:default:port: 3000protocol: HTTProutes:- name: parent-team1matches:- path:pathPrefix: /anything/team1backends:- routeGroup: team1-routesrouteGroups:- name: team1-routesroutes:- name: child-foomatches:- path:pathPrefix: /anything/team1/foobackends:- host: team1-foo.example.com:8080- name: child-barmatches:- path:pathPrefix: /anything/team1/barbackends:- host: team1-bar.example.com:8080EOF -
Run the gateway.
agentgateway -f config.yaml -
Test the routes.
# Matches parent -> delegates to team1-routes -> matches child-foocurl -i 127.0.0.1:3000/anything/team1/foo# Matches parent -> delegates to team1-routes -> matches child-barcurl -i 127.0.0.1:3000/anything/team1/bar# Matches parent prefix, but no child route matches -> 404curl -i 127.0.0.1:3000/anything/team1/other# Does not match parent prefix -> 404curl -i 127.0.0.1:3000/other
Header and query matching
Parent routes can include header and query parameter matchers that control which requests are delegated. Child routes can independently define their own matchers. A request must satisfy both the parent’s and the child’s matchers to reach a backend.
In this example, a parent route matches /anything/team1 only when the x-team header and env
query parameter are present. The route group has two child routes:
child-fooadds its own header matcher (x-role) beyond what the parent requires. A request must include both the parent’s and child’s matchers to reach the backend.child-barmatches on path only, with no additional header or query parameter matchers. Any request that the parent delegates is routed if the path matches.
-
Create the configuration file.
cat > config.yaml <<'EOF'# yaml-language-server: $schema=https://agentgateway.dev/schema/configgateways:default:port: 3000protocol: HTTProutes:- name: parent-team1matches:- path:pathPrefix: /anything/team1headers:- name: x-teamvalue:exact: team1query:- name: envvalue:exact: prodbackends:- routeGroup: team1-routesrouteGroups:- name: team1-routesroutes:- name: child-foomatches:- path:pathPrefix: /anything/team1/fooheaders:- name: x-rolevalue:exact: adminbackends:- host: team1-foo.example.com:8080- name: child-barmatches:- path:pathPrefix: /anything/team1/barbackends:- host: team1-bar.example.com:8080EOF -
Run the gateway.
agentgateway -f config.yaml -
Test the routes.
# child-foo: parent matchers + child's x-role header -> routed to child-foocurl -i "127.0.0.1:3000/anything/team1/foo?env=prod" \-H "x-team: team1" -H "x-role: admin"# child-foo: parent matchers only, missing child's x-role -> 404curl -i "127.0.0.1:3000/anything/team1/foo?env=prod" \-H "x-team: team1"# child-bar: parent matchers, child matches on path only -> routed to child-barcurl -i "127.0.0.1:3000/anything/team1/bar?env=prod" \-H "x-team: team1"# child-bar: missing parent matchers, not delegated -> 404curl -i 127.0.0.1:3000/anything/team1/bar
The backend hosts in these examples are placeholders, so a request that is routed to a child returns
503 instead of a response from the backend. The 404 responses are the ones that show a request
was not delegated.
Multi-level delegation
Child routes inside a route group can delegate to other route groups, creating a multi-level delegation hierarchy. Agentgateway detects cycles at runtime and returns an error if a delegation chain loops back to a previously visited route group.
In this example, a parent route delegates /api to a route group. One child handles /api/users
directly, while another child delegates /api/orders to a second route group with more specific
routes.
-
Create the configuration file.
cat > config.yaml <<'EOF'# yaml-language-server: $schema=https://agentgateway.dev/schema/configgateways:default:port: 3000protocol: HTTProutes:- name: parent-apimatches:- path:pathPrefix: /apibackends:- routeGroup: api-routesrouteGroups:- name: api-routesroutes:- name: child-usersmatches:- path:pathPrefix: /api/usersbackends:- host: users-service.example.com:8080- name: child-ordersmatches:- path:pathPrefix: /api/ordersbackends:- routeGroup: orders-routes- name: orders-routesroutes:- name: grandchild-listmatches:- path:pathPrefix: /api/orders/listbackends:- host: orders-list.example.com:8080- name: grandchild-detailmatches:- path:pathPrefix: /api/orders/detailbackends:- host: orders-detail.example.com:8080EOF -
Run the gateway.
agentgateway -f config.yaml -
Test the routes.
# Parent -> api-routes -> child-users (direct backend)curl -i 127.0.0.1:3000/api/users# Parent -> api-routes -> child-orders -> orders-routes -> grandchild-listcurl -i 127.0.0.1:3000/api/orders/list# Parent -> api-routes -> child-orders -> orders-routes -> grandchild-detailcurl -i 127.0.0.1:3000/api/orders/detail# Matches child-orders prefix, but no grandchild matches -> 404curl -i 127.0.0.1:3000/api/orders/other
Policy inheritance
Policies defined on a parent route are inherited by child routes in the delegation chain. If a child route defines the same type of policy, the child’s policy takes precedence.
In this example, a parent route sets a requestHeaderModifier policy that adds an x-parent header
to all requests. One child route inherits this policy, while the other overrides it with its own
requestHeaderModifier that adds a different header instead.
-
Create the configuration file.
cat > config.yaml <<'EOF'# yaml-language-server: $schema=https://agentgateway.dev/schema/configgateways:default:port: 3000protocol: HTTProutes:- name: parent-team1matches:- path:pathPrefix: /anything/team1policies:requestHeaderModifier:add:x-parent: from-parentbackends:- routeGroup: team1-routesrouteGroups:- name: team1-routesroutes:- name: child-inheritsmatches:- path:pathPrefix: /anything/team1/foobackends:- host: team1-foo.example.com:8080- name: child-overridesmatches:- path:pathPrefix: /anything/team1/barpolicies:requestHeaderModifier:add:x-child: from-childbackends:- host: team1-bar.example.com:8080EOF -
Run the gateway.
agentgateway -f config.yaml -
Test the routes.
# child-inherits: receives x-parent header from parent policycurl -i 127.0.0.1:3000/anything/team1/foo# child-overrides: receives x-child header; parent's requestHeaderModifier is overriddencurl -i 127.0.0.1:3000/anything/team1/bar
Error responses
Two invalid delegation configurations produce specific error responses, rather than being rejected at validation time.
Cyclic delegation
Agentgateway does not allow cyclic delegation. If route group A delegates to B, and B delegates back
to A, agentgateway detects the cycle at runtime and returns a 500 response. The cycle is not
caught by --validate-only, because static validation does not follow routeGroup references.
-
Create the configuration file.
cat > config-cycle.yaml <<'EOF'# yaml-language-server: $schema=https://agentgateway.dev/schema/configgateways:default:port: 3000protocol: HTTProutes:- name: parent-amatches:- path:pathPrefix: /abackends:- routeGroup: group-arouteGroups:- name: group-aroutes:- name: to-bmatches:- path:pathPrefix: /abackends:- routeGroup: group-b- name: group-broutes:- name: to-amatches:- path:pathPrefix: /abackends:- routeGroup: group-aEOF -
Run the gateway.
agentgateway -f config-cycle.yaml -
Test the route.
# group-a -> group-b -> group-a is a cycle -> 500curl -i 127.0.0.1:3000/a
Missing route group
If a route references a routeGroup that does not exist, agentgateway returns a 404 response for
that route, the same as a path with no match.
-
Create the configuration file.
cat > config-missing-group.yaml <<'EOF'# yaml-language-server: $schema=https://agentgateway.dev/schema/configgateways:default:port: 3000protocol: HTTProutes:- name: parent-missingmatches:- path:pathPrefix: /missingbackends:- routeGroup: does-not-existEOF -
Run the gateway.
agentgateway -f config-missing-group.yaml -
Test the route.
# does-not-exist is not a defined routeGroup -> 404curl -i 127.0.0.1:3000/missing