This episode puts 9router configuration on the pipeline track: automatic validation in CI with 9router validate and test runs, automated deployment of route changes, staged rollout of new policies with canary, up to safe automatic and manual rollback strategies.

In episode 18 you learned how the gateway survives when a provider falls: failover, backup routes, degraded mode, and circuit breakers. But surviving failures is only one side. The other side is preventing wrong changes from reaching production — because a model name typo, a too-low rate limit policy, or a misconfigured provider can trigger incidents as severe as a provider outage.
Episode 19 puts 9router configuration on the proper engineering track: CI/CD and deployment automation. The roadmap has three parts: validating configuration automatically in CI, deploying route changes without downtime, and doing staged rollouts of new policies that can be stopped at any time.
Routing configuration isn't a static file changed once a month. In the real world it changes daily: new models are released, provider prices change, per-customer policies shift. If every change is done manually — edit YAML on the server, restart, pray — it's only a matter of time until a small mistake reaches production.
CI/CD moves all that onto an automated track. The principle is threefold: validate before merge, deploy consistently and repeatably, and roll back quickly. None of these can be done reliably by hand in the long run.
The first layer is automated validation. Every pull request touching 9router configuration files must pass checks before being merged:
The 9router CLI provides commands for all of them:
9router validate routes.yaml
9router validate routes/ --strict
9router test run sample-requests.json --config routes.yaml--strict raises all warnings to errors — suitable for configuration heading to production. The test run command executes a set of sample requests and compares routing decisions against expectations; like a unit test for configuration.
To ensure the whole team runs the same validation, install a local git hook via the hooks configuration file:
hooks:
- id: 9router-validate
files: \.(yaml|yml)$
command: 9router validate
stages: [pre-commit, pre-push]Every YAML change will be validated automatically before commit and before push — errors stop at the developer's desk instead of waiting for a reviewer to find them.
Once validation passes and the pull request is merged, the deployment pipeline takes over. The following workflow runs in GitHub Actions: validate, deploy to staging, smoke test, then deploy to production.
name: Deploy Routes
on:
push:
paths:
- "routes/**"
- ".github/workflows/deploy-routes.yml"
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: 9router validate routes/ --strict
- run: 9router test run sample-requests.json
deploy-staging:
needs: validate
runs-on: ubuntu-latest
steps:
- run: 9router deploy routes/ --env staging
smoke-test:
needs: deploy-staging
runs-on: ubuntu-latest
steps:
- run: 9router smoke-test --env staging
deploy-production:
needs: smoke-test
runs-on: ubuntu-latest
steps:
- run: 9router deploy routes/ --env productionThis pipeline only triggers when files in the routes directory change — not on every application code commit. Each job depends on the previous one, so a bad configuration stops early. Provider credentials are never written in this file; keys are injected from secrets stored in GitHub Actions. Staging and production models also don't have to be identical — compare them before deciding on the merge with 9router diff staging production.
Deploying straight to 100 percent of traffic is a dangerous habit. New policies — raising token limits, swapping the primary model, or changing matching — can behave unexpectedly on real traffic. Staged rollout solves this by dividing traffic gradually.
The concept is similar to a canary: send 10 percent of traffic first, monitor the metrics, raise to 50 percent, then 100 percent. In 9router, this is managed through rollout configuration:
rollout:
name: migrate-chat-to-gpt-4o
stages:
- weight: 10
duration: 15m
- weight: 50
duration: 30m
- weight: 100
duration: infinite
auto_advance: true
abort_on_error: trueweight indicates the percentage of traffic directed to the new version. auto_advance makes 9router raise the weight automatically on schedule, while abort_on_error stops the rollout and returns to the old version as soon as the error rate crosses the threshold. This way every stage can be observed before the share is increased.
Not every problem is caught in the first minutes. Sometimes the error rate only stands out after several minutes. That's why the rollback strategy must have two paths ready.
Automatic rollback is triggered by defined conditions — for example an error rate above 5 percent or a p95 latency spike. When triggered, 9router restores the last healthy configuration version:
9router deploy routes/ --env production --previous
9router rollout abort migrate-chat-to-gpt-4oConfig versions are stored like code versions — every deploy produces a numbered revision. The --previous option restores the previous revision, and abort stops a rollout in progress. A team that can roll back within minutes is far braver experimenting, because every change has a way home.
Episode 19 transforms 9router configuration from "a file edited on a server" into an artifact that's tested, reviewed, and deployed like code: automatic validation in CI, a tiered pipeline from staging to production, staged rollouts with traffic weights, and a two-path rollback strategy.
Key takeaways:
In episode 20 we put all that automation to use with sharper eyes: observability at scale — metric dashboards for routes, models, and tools; anomaly detection on routing decisions; and alerting for failed or degraded routes. See you there!