Managing 9router route config professionally: route config as code, local validation, dry runs and diffs, safe rollback, as well as configuration evolution strategies for long-lived agent workflows.

In episode 9 you managed the gateway for many tenants at once. The configuration is getting large and interconnected — if managed carelessly, one small change can break routing for all customers. This is the point where configuration must be treated as strictly as code.
Episode 10 covers configuration management and versioning: declaring route config as code that enters version control, validating changes before applying them, running dry runs and diffs, preparing safe rollback, and managing configuration evolution for long-lived agent workflows. The single goal: changing routing without fear.
The first principle: all 9router configuration lives as declarative files that enter version control — not edited through a dashboard. That way every change has a history, an author, and a reason (commit message), and can be reviewed like a pull request.
apiVersion: 9router/v1
revision: 42
routes:
- name: chat-primary
match:
intent: chat
target: gpt-4o-mini
- name: chat-enterprise
match:
tenant: acme-corp
intent: chat
target: gpt-4oStore the file in the repo alongside the application, for example in the config directory. Once in git, you get all the benefits: blame to find who changed what, history to understand why decisions were made, and review to hold changes back until approved. The same release rules as code deploys can be applied to config deploys.
Info
Give an explicit revision number inside the config. This number helps distinguish the version actually deployed from versions that only exist in git, and becomes a clear reference during incidents.
Before a change is applied, the config must pass validation. 9router provides a validation command that checks the YAML structure, route references, target models, and that the policies used actually exist. This validation ideally runs in CI, right before review and merge.
npx @9router/cli validate 9router.yamlChecking 9router.yaml ... ok
- routes: 14 defined, 0 orphan
- policies: 5 defined, all referenced
- models: 8 targets resolve
- warnings: 2 (route chat-legacy never matched)Notice the output warns about chat-legacy, which never matches any request. A good validator doesn't just reject broken config; it also flags dead configuration. Removing unused routes reduces cognitive load and the surface for errors. Run npx @9router/cli validate on every commit and reject the merge if there are errors.
Even when the config is structurally valid, validation doesn't guarantee the desired behavior. That's what the dry run is for: simulate the change against real traffic (or a set of sample requests) and see the impact before deploying. A dry run answers "what percentage of traffic will change direction?".
npx @9router/cli dry-run 9router.yaml --replay traffic.json{
"replayed": 10000,
"route_changed": 321,
"model_changed": 289,
"policy_blocked_new": 12,
"top_shifts": [
{ "from": "chat-primary", "to": "chat-enterprise", "count": 210 }
]
}Pair it with diff to see the comparison between two config versions explicitly: npx @9router/cli diff 9router-v41.yaml 9router-v42.yaml shows the routes and policies added, removed, or changed. Combining dry run and diff gives a complete picture: what changed structurally and what the behavioral impact is.
Despite all the validation, a change can still go wrong in production. Safe rollback needs three things: the old configuration still available, a fast way back, and a limited blast radius. 9router keeps the history of deployed revisions, so rollback is just choosing the previous revision.
npx @9router/cli revisions list
npx @9router/cli rollback --to revision:41 --scope route:chat-primaryWith scope, you can roll back just one problematic route instead of the whole config. This dampens the risk: one failed route doesn't force every tenant back to the old version. Record every rollback in the log with its reason, and turn the moment into a lesson — rollbacks usually happen because of conditions not covered by the dry run.
Warning
Rollback is not a substitute for testing. If you routinely roll back for the same problem, that's a signal there's a gap in validation or the dry run — fix the root cause, don't just keep pressing the rollback button.
Long-running agent workflows — hundreds of thousands of requests in a single flow — face a unique challenge: a route that's correct when the flow starts can be wrong when the flow ends. Versioning helps, but it needs a strategy so evolution doesn't break in-flight flows.
policies:
- name: pin-agent-revision
rules:
- id: pin-revision
type: constraint
if:
agent_flow: true
then:
pinned_revision: 41The strategy: an agent flow is "pinned" to a specific config revision when it starts, so routing decisions stay consistent throughout the flow. New config versions only apply to newly started flows. This separates two speeds: old flows finish with their old rules, new flows enjoy the new rules. Add a transition mechanism — for example giving old flows a deadline to move to the new revision — so nothing gets stuck on outdated config forever.
9router configuration deserves to be treated as a production artifact: version control for history, local and CI validation to prevent errors, dry runs and diffs to understand impact, scoped rollback for fast recovery, and revision pinning to keep long-lived agent flows safe. Managing config with this discipline turns routing changes into a calm routine, not a risky event.
Key takeaways:
In episode 11 we secure all of that foundation: Secrets & Integration Security — storing API keys and provider credentials safely, secure integration with external toolchains, and rotation and least-privilege strategies. See you there!