The Decision That Shapes Everything
Most early-stage SaaS products start as single-tenant systems — one database, one deployment, one set of configuration values. It works fine for your first 10 customers. Then you win a 500-seat enterprise deal, and suddenly you are scrambling to retrofit tenant isolation into a system that was never designed for it.
The right time to design for multi-tenancy is before you have your first paying customer. This post walks through the three primary isolation models, when to use each, and the implementation tradeoffs that will affect every engineering decision downstream.
The Three Isolation Models
1. Database-per-Tenant
Each customer gets their own dedicated database. This is the highest isolation model and the most expensive to operate.
Use this when: You are selling to regulated industries (healthcare, fintech, legal) where a customer contractually requires data sovereignty, or when customers have wildly different compliance needs that would be impossible to satisfy with a shared database.
The real cost: At 100 tenants, managing 100 database instances is manageable with good infrastructure automation. At 1,000 tenants, you need a database-per-tenant provisioning pipeline, automated backup management, and a way to apply schema migrations across all instances without taking your system offline. Most teams underestimate this operational overhead by a factor of 10.
2. Schema-per-Tenant
A single database contains multiple schemas — one per tenant. PostgreSQL supports this natively. Your application switches the search_path at the beginning of each request.
Use this when: You need strong logical isolation without the operational overhead of managing separate database instances. Works well for 10–500 tenants before connection pool exhaustion becomes a concern.
The hidden problem: Schema migrations. Every time you add a column or create a table, you need to run that migration across every tenant schema. At 200 tenants, a 30-second migration becomes 100 minutes if run serially. You need a migration orchestration layer that applies changes in parallel and handles partial failures gracefully.
3. Row-Level Isolation (Shared Schema)
All tenants share the same tables. Every row has a tenant_id foreign key, and your application filters by that key on every query.
Use this when: You are building for SMBs or prosumer audiences where cost efficiency matters more than compliance requirements. This model supports thousands of tenants on modest infrastructure.
What keeps engineers up at night: Missing a WHERE tenant_id = ? clause on a single query is a data leak. The standard mitigation is to enforce tenant scoping at the ORM layer, not in application code. In TypeORM, this means using entity subscribers or a custom repository base class that automatically appends the tenant filter. In Prisma, you wrap the client in a middleware that injects the filter. The point is: the filter must be unforgeable from application code.
The Architecture We Recommend for Most B2B SaaS
For most B2B SaaS products — particularly those targeting SMB to mid-market — we recommend starting with row-level isolation with a clear upgrade path to schema isolation for enterprise customers who require it.
This means designing your tenant abstraction layer correctly from day one:
- A
TenantContextthat is populated at the authentication layer from the JWT or API key. - All repository calls go through a
ScopedRepositorythat automatically applies the tenant filter. - An admin bypass mechanism that is only available to internal tooling, never customer-facing code.
- Tenant provisioning as a first-class workflow — not a manual database operation.
Custom Domains and White-Labelling
Enterprise customers almost always want their own domain. app.yourclient.com instead of yourproduct.com/yourclient. This requires tenant resolution from the hostname rather than the URL path.
The implementation: a wildcard DNS record pointing to your application servers, a middleware layer that extracts the subdomain or full custom domain, maps it to a tenant ID via a database lookup (cached in Redis for performance), and injects the tenant context for the rest of the request lifecycle.
The operational requirement: an automated TLS certificate provisioning flow. Manual certificate management for custom domains does not scale past 10 enterprise customers. Look at Let's Encrypt with certbot or AWS Certificate Manager with Route 53 automation.
Feature Flagging by Plan
Multi-tenant SaaS almost always needs plan-based feature gating. The wrong way to do this is a series of if (tenant.plan === 'enterprise') checks scattered through your codebase. This becomes unmaintainable within 6 months.
The right way: a feature flag system where each plan maps to a set of feature keys, and your code checks featureFlags.isEnabled('advanced_analytics', tenantContext). The flag resolution logic is centralised, testable, and queryable. When you launch a new plan, you configure it in one place, not across 40 files.
The Bottom Line
The tenancy model you choose in week one will constrain or enable every architectural decision you make for the next five years. Choose it based on your customer profile, compliance requirements, and realistic growth projections — not on what is easiest to build today. The cost of retrofitting tenant isolation into a system that was never designed for it is always higher than designing for it upfront.
