TenantsDB is live.
A separate database for every tenant. Not schemas. Not row-level filtering. Actual isolated databases.
PostgreSQL, MySQL, MongoDB, Redis. One API to manage them all.
Start with 5 free tenants: https://t.co/mSNMByB4SH
With database-per-tenant, this is one command. That customer's backup contains only their data, the restore touches only their database, every other customer is untouched.
Why shared backups are the multi-tenant risk nobody audits:
https://t.co/IPx7dIA9e5
A customer emails: "we deleted something important, can you restore our data from Tuesday?"
Your nightly backup is one file containing all 400 customers.
So "restoring" means: spin up a scratch instance, load 200GB, pull one tenant's rows out of every table, then merge them back into live prod without breaking a single foreign key.
At 2am. While they wait.
@arximughal What if it wasn't expensive at all? what if spinning up a tenant DB was as easy as inserting a row? what if separate migrations, connection pools, and monitoring all sat behind a single API?
@hiranyalp4 Spot on. The routing abstraction is the cheapest engineering you'll ever do today and the most expensive one you'll ever do in eighteen months.
We used RLS for two years in production. The honest answer: it works until it doesn't.
RLS is a filter that runs inside the database, which is strictly better than a WHERE clause in app code, because developers can't forget to write it. That part is real and useful.
What it isn't: isolation. It's still one shared database, one shared cache, one shared connection pool, one shared autovacuum. A policy bug, a missing SET app.current_tenant on a pooled connection, or a BYPASSRLS role somewhere in the stack and you're back to leaking. The failure mode is silent. No 500 error, just wrong data returned to the wrong tenant.
We ended up moving to database-per-tenant.
@meaningoflights Here's the tenant view in the dashboard. Each tenant has its own connection string, isolation tier per engine, and one-click actions for backups, PITR, zero-downtime upgrade, and region change.
Building multi-tenant infrastructure yourself takes 9 to 17 months.
Tenant routing. Schema migration across N tenants. Per-tenant backups. Connection pooling. Search. Moving big customers to dedicated infrastructure. Rate limiting.
Each piece is "a sprint or two." The total is most of your first year.
https://t.co/vFhi5ttHNf
Worth clarifying the model. The differentiator is not failover speed, it's the unit of abstraction.
AWS sells databases. One RDS instance. One DocumentDB. One ElastiCache Redis. Each is a separate service with its own API, its own failover config, its own backup schedule. If you want per-customer isolation across four engines, you build the orchestration yourself with Lambda, Step Functions, and CloudFormation. AWS has no concept of "tenant" that groups a customer's PG + MySQL + Mongo + Redis under one identity.
TenantsDB sells tenants. One API call creates a tenant across all four engines, with isolated databases, deployed schemas, routing, backups, and rate limits configured. One API call upgrades that tenant from shared to dedicated infrastructure with sub-2-second cutover. One API call moves them to a different region. The customer never thinks about which engine lives where.
On failover specifically: customer databases use native logical replication (PG PUBLICATION/SUBSCRIPTION, MySQL binlog, Mongo change streams) with snapshot-based recovery and point-in-time restore. Automatic cross-region promotion is on the roadmap. For customers who specifically need RDS-style automatic Multi-AZ today, AWS-hosted dedicated infrastructure is available, the piping is in the system, priced separately for enterprise.
@tristanbob RLS is brittle by design. Every table needs a policy, every join respects it, one missed rule leaks. AI agents make it worse because the policies span files they can't all see at once.
Per-tenant DB skips the problem. Connection is the boundary. https://t.co/mSNMByB4SH
@Alacritic_Super All tenants in parallel, not one at a time. TenantsDB analyzes the shared DB, traces FK paths from the tenant column, then provisions and imports every tenant's slice concurrently. App stays live, cutover is a connection string swap.
Full pattern: https://t.co/3i43DaxTyE
@Alacritic_Super Wrote up the longer version: https://t.co/Fg5AkDLorB
Why every control on the list lives in the same bug radius, and what physical isolation actually means for AI copilots.
@Alacritic_Super Every control on the list is logical isolation in shared infrastructure.
Vector indexes, namespaces, RBAC, encryption. All enforced in the same process that had the bug.
Physical DB per tenant is the only control outside the bug radius.
Separate database per tenant, but the answer depends on tenant count and isolation needs. Shared tables scale operationally but break for compliance-heavy workloads (legal, medical, fintech) and for AI agents where cross-tenant retrieval is silent contamination.
Separate schemas is the awkward middle: most operational pain of per-DB without the isolation guarantees. Per-tenant DB is the right answer when you need physical isolation, the operational cost is solvable
Good framing. Answers when the data layer is per-tenant database (which is what we do at TenantsDB):
Tenant isolation at retrieval is physical. Each tenant's data lives in their own database, the agent's connection only sees one tenant's records.
The agent can't access another client's embeddings because it doesn't have credentials for another client's database. Cross-tenant access requires a different connection, not a different query.
Isolation is enforced by the database itself. Application logic doesn't have a path to bypass it.
RLS works for shared-table architectures. Per-tenant DB removes the failure mode entirely because there's nothing to bypass.
Nice. Async connection acquisition as the seam is exactly the right design choice, it's what makes per-tenant routing pluggable rather than a rewrite. If you ever want to test Deltic against a per-tenant DB backend, happy to help you set up TenantsDB as one of the implementations. Would be interesting to see the abstraction hold up against actual N-database routing.
Data layer. Per-tenant database for state, embeddings, conversation history, RAG indexes. Multi-tenant AI platforms hit this in year 1 because every customer's context has to stay isolated. Built TenantsDB to solve it. K8s + Kueue + Karpenter + GPUs handles compute, but you still need per-customer data that doesn't leak across tenants.
Makes sense as a default. The interesting design question is whether the storage abstraction can swap in a per-tenant DB backend without leaking the change up the stack. We do per-tenant DBs at TenantsDB and the connection routing and pool logic is the part most abstractions struggle to hide. Worth thinking about as you scope the higher-isolation implementations.
Your TypeScript components project sounds interesting. Are you doing tenant isolation at the schema level (per-tenant schemas in shared DB) or per-tenant database? The composability framing for event sourcing + mutexes + tenant isolation is the right shape; the answer mostly depends on which isolation level you're targeting.
The honest reason most teams pick the explicit user_id column over cluster-per-customer isn't that they prefer it. It's that the operational tax (provisioning, schema across N clusters, routing, per-tenant migration, backups) used to be a year of infra work. That's the actual gate. Once that tax goes to zero, the calculus flips.