If you keep Claude Code, Codex CLI and Cursor open at the same time, you have probably lived through this: one tool still has half its quota, another is rate-limited into uselessness, and you own other accounts and a few cheap API keys but cannot be bothered to rewrite the config every time. That is the problem 9Router addresses — run one OpenAI-compatible endpoint locally, point every CLI tool at it, and let it decide which upstream each request goes to.
Set expectations first: 9Router is a router for your own machine, not a team gateway. There are no multiple users, no billing splits; data lives in a local SQLite file. Handing access out to a team and accounting for it per person is the job of Sub2API or LiteLLM.
Everything below was done once on an Apple Silicon Mac, using 9router CLI 0.5.65 from npm. The repository, decolua/9router, is MIT-licensed, built mostly on Next.js, and had roughly 27,000 stars when this was checked.
How the routing actually works
Figure 1: The project calls this "smart three-tier switching" — burn through what you have already paid for, then fall to low-cost APIs, then to free tiers. You have to connect all three tiers yourself; it does not conjure quota out of nowhere.
Beyond routing, 9Router does two things that matter more day to day. The first is format conversion: CLI tools speak the OpenAI dialect, upstreams may only accept Claude or Gemini formats, and the translation happens in the gateway — which is how a tool ends up talking to a model it never supported. The second is token compression (the project calls it RTK): output from git diff, grep and ls routinely eats a third of the context budget, so it gets compressed before being sent. The vendor claims 20–40% savings on input tokens; how much you actually see depends on how tool-call-heavy your workflow is.
Installing, plus one thing to change immediately
npm install -g 9router
9routerNode.js 18 or newer is required. Typing 9router starts the service and opens a browser. The useful flags:
9router --help
-p, --port <port> port, default 20128
-H, --host <host> bind address, default 0.0.0.0
-n, --no-browser do not open a browser
-l, --log print server logs (hidden by default)
-t, --tray run in the system tray
--skip-update skip the auto-update check`-H` defaults to `0.0.0.0`, and you should override it on the first run:
9router --port 20128 --host 127.0.0.1 --no-browser --logThe reason comes in a moment. The startup log tells you which storage implementation it picked, which is handy when debugging:
🚀 9router v0.5.65
Server: http://127.0.0.1:20128
[DB] better-sqlite3 unavailable: Cannot find module 'better-sqlite3'
[DB] Driver: node:sqlite | file: ~/.9router/db/data.sqlite
[DB][migrate] applied #1 initialbetter-sqlite3 is a native module; when it will not build, the app falls back to Node's built-in node:sqlite with no loss of function. Everything — account credentials, API keys, usage records — lives under ~/.9router/. Set DATA_DIR to move it, and back it up by archiving that one directory.
The default password is 123456, and that is not a joke
Opening http://127.0.0.1:20128 for the first time lands on a login page:
Figure 2: The login page on a fresh install. The default password of 123456 is printed on the page, and the orange line underneath admits this is a security risk.
The wording says you will be asked to set a password when logging in remotely — meaning local access never forces you to change it. Combine that with the default 0.0.0.0 bind and anyone on the same Wi-Fi who reaches port 20128 can type 123456 and see every credential and API key you have connected.
So the order should be: start with --host 127.0.0.1, change the password in Settings as the very first action after logging in, and only then consider widening the bind address. You can also set INITIAL_PASSWORD before the first start and skip the default entirely.
The four pages that matter
Endpoint & Key: the address your tools need
Figure 3: The Endpoint & Key page. That http://127.0.0.1:20128/v1 on the left is the base URL every CLI tool needs; the Default Key below is issued by the gateway itself and has nothing to do with upstream accounts.
Two switches deserve attention. Require API key rejects requests without a valid key — fine to leave off when it is only ever local, mandatory the moment you expose it through Tunnel or Tailscale. And the warning next to the Tunnel row is fair: change the default dashboard password before activating the tunnel. Publishing a console still protected by 123456 through a public tunnel puts every stored credential on the open internet.
Before you connect a single provider, the model list is already not empty:
curl -s http://127.0.0.1:20128/v1/modelsI counted 624 models across 70 provider prefixes. That is the built-in catalogue — the prefix is the provider, so cc/ is Claude Code, cx/ is Codex, gh/ is GitHub Copilot, kr/ is Kiro — and whether any of them actually answers depends on which accounts you have linked.
Providers: where accounts get connected
Figure 4: Providers comes in three groups. OAuth goes through a browser authorisation, most of the free tier needs no signup, and forty-odd conventional vendors sit below waiting for an API key.
The groups differ by how you connect:
- OAuth Providers — Claude Code, OpenAI Codex, GitHub Copilot, Cursor IDE and similar. One browser authorisation, after which tokens refresh automatically with no manual re-login. This group connects subscriptions you already pay for.
- Free Tier Providers — OpenCode Free, Kiro AI, Gemini CLI, the Vertex AI trial credit and others; some need no registration at all.
- API Key Providers — Anthropic, DeepSeek, Azure OpenAI, Groq, GLM, Baidu Qianfan and about forty more; paste a key and go.
At the top there is also Custom Providers, where you can add any OpenAI- or Anthropic-compatible endpoint by hand. If you already run your own gateway — the LiteLLM instance from the previous article, say — plug it in here.
CLI Tools: it rewrites the config files for you
Figure 5: The CLI Tools page scans for locally installed tools and shows whether each already points at 9Router. Opening one lets it rewrite that tool's config file directly.
The convenience here is not having to hunt for config files. Doing it by hand is not hard either:
# Codex CLI
export OPENAI_BASE_URL="http://127.0.0.1:20128"
export OPENAI_API_KEY="your-9router-key"// Cline / Continue / RooCode and friends: choose OpenAI Compatible, then
// Base URL: http://127.0.0.1:20128/v1
// API Key: copy it from the Endpoint & Key page
// Model: a prefixed name such as cc/claude-opus-4-7, or a combo you createdA trap people hit repeatedly: write `127.0.0.1`, not `localhost`. Some tools on macOS resolve localhost to IPv6 ::1 while the service only listens on IPv4, and the symptom is "the service is clearly running but nothing connects."
At the bottom of the page sits a MITM Tools group (Antigravity, GitHub Copilot, Kiro). Those integrations work by running a local man-in-the-middle proxy against the IDE's traffic, which requires trusting a locally generated certificate. It is technically sound, but it changes the trust chain of your entire machine, and the terms of service of those IDEs generally do not welcome the approach — unless you know exactly what you are doing, skip this group; the other three connection types already cover normal use.
Combos: turn a fallback chain into a model name
The Combo & Vision Adapter page lets you order several models into a chain and expose it downstream as a single model name:
Combo name: my-coding-stack
1. cc/claude-opus-4-6 (your own subscription, use it up first)
2. glm/glm-4.7 (low-cost backup)
3. if/kimi-k2-thinking (free fallback)Downstream only ever names my-coding-stack, and the router steps down the list on quota exhaustion or errors. The Quota Tracker page shows remaining allowance and reset countdowns per upstream (five-hourly, daily, weekly), which is the single most useful page in the product — at minimum it tells you how much of your subscription is about to expire unused.
Running it in Docker
To keep it resident on a NAS or a small server, the official image is decolua/9router, built for amd64 and arm64:
docker run -d \
-p 127.0.0.1:20128:20128 \
-v "$HOME/.9router:/app/data" \
-e DATA_DIR=/app/data \
-e INITIAL_PASSWORD='use-a-real-password-here' \
--name 9router \
decolua/9router:latest`DATA_DIR=/app/data` is not optional — without it the container writes elsewhere, the bind mount does nothing, and deleting the container takes the data with it. The port mapping is prefixed with 127.0.0.1: for the same reason as before. Upgrading means docker pull and recreating the container; the data in the mount is untouched.
If upstream calls need a proxy, HTTP_PROXY, HTTPS_PROXY, ALL_PROXY and NO_PROXY are all supported, in either case.
Compliance and risk: please read this section
The 9Router repository describes itself with "Unlimited FREE AI coding" and "never hit limits." That is stirring copy, but treating it as a promise means you carry the risk:
- Free tiers are not unlimited. Every free provider in tier three has its own quota and terms; chasing "unlimited" by rotating batches of registered accounts is exactly what their abuse clauses cover, and the outcome is a ban.
- Subscriptions have a defined scope. Wiring your own Claude Pro or Copilot subscription into a local router for personal use is one thing. Turning it into a shared endpoint for several people is another, and most vendor agreements prohibit the second.
- There are many identically named repositories. Search results are full of near-identical forks. Projects in the "free model" genre are a prime target for supply-chain tampering — you are handing over OAuth credentials, and a handful of changed lines is enough to ship them elsewhere. Install only from [decolua/9router](https://github.com/decolua/9router) or the official `9router` package on npm, and check the publisher before you do.
- Credentials sit in plaintext reach on your machine.
~/.9router/db/data.sqliteholds tokens for every account you have connected. The security level of that machine is the security level of all your AI accounts.
In one line: treating it as a way to manage the accounts you already have is reasonable; treating it as a way around limits eventually costs you something.
Who should use it, who can skip it
A good fit: individual developers with two or more AI coding subscriptions or API keys, who bounce between Claude Code, Codex and Cursor, and who want to see how much of each subscription is left. Quota visibility and one-click switching are genuinely smoother here than editing environment variables by hand.
Can skip it: anyone on a single subscription with a single tool — the extra layer is just another thing that can break. Teams that need account distribution and accounting should look at Sub2API; anyone who needs complex routing policies and per-team budgets should look at LiteLLM.
Be prepared for: extremely fast iteration — the changelog gains several entries a day, and the UI and menu structure move around. The screenshots here are 0.5.65, and whatever you install is likely to look different. Also, the 9router-app package in the repository is private, so community code review is limited; that is worth weighing before you hand it your subscription credentials.
Alternatives
- [LiteLLM](/articles/litellm-gateway-deployment-guide): configuration as code, far more expressive routing and budget control, but no OAuth-a-subscription flow and no automatic configuration of local CLI tools.
- [OpenRouter](/tools/openrouter): a hosted service, one key for hundreds of models, nothing to maintain — at the cost of every request passing through a third party.
- Switching environment variables by hand: with two upstreams and infrequent switching, two shell aliases genuinely solve this. You do not need to install anything.
Sources and how they were checked
- decolua/9router repository — feature descriptions, provider lists, licence and star count.
- DOCKER.md in the repository — image name, port,
DATA_DIRand the data directory layout. - npm · 9router — CLI version number and Node version requirement.
The screenshots, startup logs and /v1/models counts come from a clean install performed on 2026-09-04. Version numbers, the provider roster, the model count and the UI layout are all volatile, particularly the free tier, where suppliers withdraw or change terms without notice; treat everything here about quotas and pricing as needing confirmation against the UI on the day you install.