You’re building a SaaS product. Do you give each customer their own database? Put everyone in one? Somewhere in between? The answer affects cost, isolation, compliance, and how much operational pain you take on for the life of the product.

The Three Models#

Shared database, shared schema: all tenants in the same tables, with a tenant_id column. One database to manage. Lowest cost. The risk: a bug that forgets the tenant_id filter leaks one customer’s data to another. Row-level security can enforce isolation, but you need to trust it’s configured correctly everywhere, and every query needs to be written defensively.

Shared database, separate schema: each tenant gets their own schema (namespace) within the same database instance. Data is logically isolated. A query on Tenant A’s schema can’t accidentally touch Tenant B’s tables. You still share one database process, so a misbehaving tenant affects database-level resources like connections and buffer pool.

Separate database per tenant: full isolation. A bug in one tenant’s data path can’t affect another. You can place tenants in different regions for compliance. The cost: potentially thousands of database instances to manage. Schema migrations need to run against each one.

graph TD A[Shared DB - shared schema] --> D[tenant_id column in every table] B[Shared DB - separate schema] --> E[schema_tenant_a.orders, schema_tenant_b.orders] C[Separate DB per tenant] --> F[db_tenant_a, db_tenant_b on separate instances] D --> G[Lowest cost - highest cross-tenant risk] E --> H[Medium cost - logical isolation] F --> I[Highest cost - strongest isolation] style A fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style B fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style C fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style D fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style E fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style F fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style G fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style H fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style I fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff

Compliance Drives the Decision#

For early-stage SaaS, shared schema is fine. The moment you sell to enterprise customers with data residency requirements (EU data must stay in the EU, healthcare data must be isolated), shared schema becomes a liability. You end up doing the migration under deadline pressure instead of making the architectural choice upfront.

Hybrid models are common: small customers on shared schema, large enterprise customers on dedicated databases. The application needs routing logic to know which path each tenant takes.

At Salesforce#

Salesforce uses a hybrid model. Standard customers share infrastructure with others in the same “pod” (a cluster of servers and databases). Larger enterprise customers on specific plans get isolated pods. The metadata about which customer is on which infrastructure lives in a routing layer that every request passes through.

I worked on internal tooling that managed this routing table. When a new enterprise customer was provisioned, the entry in the routing table determined which database cluster their data landed on. Getting that wrong sent their data to the wrong cluster entirely.

What I’m Learning#

The tenancy model is hard to change later. I’d err toward separate schemas even at small scale. Migrating shared-schema data to separate schemas while the product is live is painful. The cost difference is small until you have thousands of tenants.

Which tenancy model are you on, and have you had to migrate between models?