By Huzefa Motiwala · Co-Founder & Chief Product Officer

TL;DR
You shipped fast. Every tenant lives in one shared database, a tenant_id column on each table, one schema to migrate. It worked for the first two hundred customers. Then a mid-market account ran a report that locked a table for ninety seconds, and three other tenants opened support tickets at the same moment. Or a prospect’s security team sent a questionnaire asking where, exactly, their data is stored, and “in the same table as everyone else” was not an acceptable answer.
This is the multi-tenant architecture wall, and almost every SaaS company hits it. The question is not whether shared or isolated is “better.” It is which model each tenant needs right now, and how to move a tenant across the line without downtime when its needs change.
The short version: start pooled for speed, isolate specific tenants when compliance or load forces your hand, and design from day one so that move is a migration, not a rewrite.
Multi-tenant isolation comes in three shapes, and AWS names them silo, pool, and bridge in the SaaS Lens. The difference is where the boundary between tenants sits: at the resource level, at the row level, or somewhere in between.
tenant_id filter on every query. Cheapest to run, hardest to guarantee.Microsoft frames the same spectrum in its tenancy models guidance: a shared app tier can sit on top of isolated databases, letting you pick a different isolation level for each layer of the stack.

Pool wins on cost and operational simplicity. One schema change, one backup job, one monitoring dashboard covers everyone. Silo wins on isolation, blast radius, and compliance, at the cost of multiplying every operational task by your tenant count. Here is the honest side-by-side.
| Dimension | Pool (shared schema) | Silo (database-per-tenant) |
|---|---|---|
| Cost per tenant | Low, shared infrastructure | Rises linearly with each customer |
| Isolation strength | Logical, query-enforced | Physical resource boundary |
| Blast radius | All tenants at once | One tenant |
| Noisy neighbor | Real risk | Eliminated |
| Compliance (HIPAA, PCI, SOC 2) | Harder to attest | Much simpler to attest |
| Schema migration | One run, one time | Run against every tenant DB |
| Per-tenant scaling | Difficult to isolate | Natural, tune per tenant |
In a pooled database, one tenant’s heavy query load can degrade performance for everyone sharing that instance. This is the noisy-neighbor problem, and it is the most common reason teams start looking at isolation. You can soften it inside the pool with per-tenant rate limiting, connection quotas, and query timeouts before you reach for a full silo. We cover the query-side of this in our notes on application-level caching, which often buys you a year of runway before any migration.
Database-per-tenant makes it far easier to attest to standards like HIPAA, PCI-DSS, and SOC 2, because you can point an auditor at a dedicated resource rather than explaining row-level filtering. In a pooled model that row-level boundary rests on your authorization layer, RBAC or ABAC, being correct on every query path, which is exactly what an auditor will probe. When a regulated or enterprise customer writes data residency or dedicated-storage into the contract, logical isolation stops being enough. That is a hard line, not a preference.
Switch by signal, not by schedule. Most tenants should stay pooled for their entire life. You move an individual tenant to a silo when one of these fires, and you move only that tenant, not the whole fleet.

Notice what is not on that list: raw tenant count. Scaling by number of tenants alone is a pooling problem, not a silo trigger. Postgres with Citus sharding by tenant_id can pack millions of tenants across shards while keeping each tenant’s data co-located on one node. Density is cheap. Isolation is what costs money, so spend it only where a real requirement demands it.
The migration itself is a re-platform for one tenant, and the playbook looks a lot like our zero-downtime migration approach: dual-write, backfill, verify, cut over, decommission. The deployment architecture that makes this safe is the same one that makes any risky change safe: you can route a single tenant’s traffic independently and roll it back in seconds.
The whole thing depends on a decision you make on day one, long before any tenant needs to move. Every table needs a tenant_id, and every query needs to filter on it. Skip that, and the eventual split is a data-archaeology project instead of a routing change. This is one of those architecture decisions that are hard to reverse, so it belongs in your first schema, not your Series B.
The pattern we see most is a team that chose pool for speed, grew past the point where a shared instance was comfortable, and treated “go database-per-tenant” as an all-or-nothing rewrite. It almost never needs to be. The bridge model lets you keep ninety-plus percent of tenants pooled, where they are cheap and easy to operate, and silo only the handful that carry compliance weight or generate real load.
We usually start by getting the tenant model right at the data layer, the same discipline we apply when choosing between Postgres and MongoDB or designing for high transaction volume. Get the boundary right first, then the migration is a mechanical, reversible operation rather than a bet-the-company event. Pooled tenants keep their cost advantage. The one enterprise tenant gets its walled-off floor. Nobody takes downtime.
If you are staring at a shared schema and a compliance questionnaire you can’t answer yet, that is the situation we are built for. Start here: the deployment architecture behind a safe switch, no pitch, just the mechanics.
Neither is universally better. Multi-tenant pooling is far cheaper to run and operate at scale, which is why most SaaS starts there. Single-tenant isolation (the silo model) is better when a specific customer carries a compliance regime, a data-residency clause, or load heavy enough to harm neighbors. The practical answer for a growing product is a bridge model: pool most tenants, isolate the few that need it.
It is when one tenant’s heavy activity, a large report, a runaway query, a bulk import, consumes shared resources and slows the database for every other tenant on the same instance. In a pooled architecture all tenants share compute and I/O, so there is no hard boundary stopping one from starving the others. You mitigate it with per-tenant rate limits, connection quotas, and query timeouts, and you eliminate it by moving that tenant to a dedicated database.
Yes, it makes attestation simpler. With a dedicated database you can show an auditor a physical resource boundary rather than explaining and proving that row-level tenant_id filtering is applied correctly on every query path. It also makes per-tenant encryption, retention, and backup policies straightforward. It does not make you compliant by itself, but it removes a large class of shared-data risk from the conversation.
Far more than most teams expect. Sharing a schema scales by tenant count very well, and with sharding by tenant_id (for example using Citus on Postgres) you can distribute millions of tenants across nodes while keeping each tenant’s data co-located. Tenant count alone is rarely the reason to isolate. The reasons to isolate are compliance, blast radius, and noisy-neighbor load, not the size of the tenant list.