Why Postgres Is Our Only Database of Record
Credits, tenancy, and inference state all live in one Postgres instance — no second database of record, no Docker. Here is why one database simplifies the hardest invariants an LLM gateway has to hold.
A surprising amount of distributed-systems pain is self-inflicted: you reach for a specialized datastore, and now you own consistency between stores. NemoRouter made the opposite bet. Credits, organizations, keys, guardrails, logs, and the inference layer's own tables all live in one Postgres instance. There is no second database of record, no BigQuery, no Firebase, no local Postgres in a Docker box. This post is why one database makes the gateway's hardest invariants easy.
The bet: one database of record
ONE Postgres instance
├─ nemo schema (Supabase-managed: credits, orgs, keys, guardrails, logs…)
└─ public schema (LiteLLM/Prisma-managed: org, team, key, spend tables)Two schemas, two migration owners, one database. NemoRouter's feature tables and LiteLLM's tables share the same Postgres. That single fact is what powers the same-UUID architecture: an authorization check can join our tables against LiteLLM's membership table directly, because they're in the same database with the same UUIDs. No cross-store sync, no eventual consistency between systems.
Why one store simplifies the hard invariants
The gateway's two scariest invariants are both transactional, and transactions are exactly what a single database gives you for free:
- Credits never go negative, and balance always matches the ledger. This is one transaction: update the balance and write the ledger row together, or neither. (See reserve-and-settle.) Split the balance and the ledger across two stores and you've turned an atomic write into a distributed-transaction problem with no good answer.
- Tenant isolation is enforced at the row. Row-level security scopes every query to the caller's org/team. That's a database feature; spreading data across stores means re-implementing RLS in each, inconsistently.
The cheapest distributed system is one node
Every datastore you add is a new consistency boundary you now own. A second store for "analytics" or "caching as a source of truth" buys a feature and a whole class of sync bugs. Keeping one database of record means the money invariants are plain SQL transactions, not saga orchestration.
"No Docker, no local Postgres" — and why
We don't run a local Postgres in a container for development either. The reason isn't dogma — it's that a local database that differs from production (different extensions, different RLS behavior, different migration state) is a source of "works on my machine" bugs precisely in the area you can least afford them: tenancy and money. Developing against the same managed Postgres (with proper tenant scoping) keeps the environment honest. The database you test against behaves like the one you ship to.
Two migration engines, one rule: never cross
One database with two schema owners needs exactly one discipline: they never touch each other's tables. Alembic owns the nemo schema; Prisma (inside the LiteLLM dependency) owns public. We never create tables in public (Prisma would drop them on its next migration), and Prisma never touches nemo. When LiteLLM's schema drifts, we apply additive, idempotent hotfixes (ADD COLUMN IF NOT EXISTS) rather than letting an automatic push rewrite tables — a push once wiped LiteLLM tables in production, so destructive auto-migration is hard-disabled. Two owners, one database, a clear boundary between them.
What about caching?
Single-database-of-record doesn't mean single-place-for-everything. Hot config is cached in-process briefly (org config for ~30s) to avoid hammering the database on every request. The distinction that matters: caches are derived and disposable — losing one costs a re-read, never a fact. The source of truth — every credit, every key, every ledger entry — is Postgres, and only Postgres. A cache that became a source of truth would reintroduce exactly the consistency boundary we avoided.
The takeaway
The hardest things an LLM gateway must guarantee — non-negative credits, balance-equals-ledger, tenant isolation — are transactional and relational, which is exactly what one Postgres instance does well. Keep one database of record, two well-fenced schema owners, and caches that stay disposable, and you trade a pile of cross-store consistency problems for plain SQL transactions. The most reliable distributed system is the one you didn't distribute.