Related: React vs Next.js in 2026: Which Should You Use? (Honest Comparison)
Multi-tenancy is the core architecture decision in any SaaS. It is how one running system serves many customers (tenants) while keeping each one's data separate and private. Get it right and you scale cheaply with strong isolation. Get it wrong and you face data leaks, slow tenants dragging down fast ones, and a painful rebuild later. This guide covers the three tenancy models, how to isolate data, and how to choose.
Key takeaways
- There are three models: database per tenant (silo), shared schema with a tenant id (pool), and schema per tenant (bridge).
- Shared schema is the cheapest to run and the hardest to isolate. Database per tenant is the strongest isolation and the most expensive to operate.
- Row level security in the database is your safety net so one tenant can never read another's rows.
- Watch the noisy neighbour problem: one heavy tenant should not slow everyone else.
- Most startups should start pooled and move heavy or regulated tenants to their own database later.
The three tenancy models
Every model answers one question: how separate is each tenant's data? The three common answers sit on a line from fully shared to fully separate.
| Model | Isolation | Cost to run | Best for |
|---|---|---|---|
| Pool (shared schema, tenant_id column) | Logical only | Lowest | Many small tenants, fast growth |
| Bridge (schema per tenant) | Medium | Medium | Mid size, some custom needs |
| Silo (database per tenant) | Strongest | Highest | Enterprise, regulated, large tenants |
You do not have to pick one forever. A common and healthy pattern is a hybrid: pool most tenants for cost, and give your biggest or most regulated tenants their own database for isolation and performance.
Data isolation and row level security
In the pooled model, every table carries a tenant_id and every query must filter by it. The danger is obvious: one missing WHERE tenant_id = and a customer sees another customer's data. Application code alone is too easy to get wrong. The fix is to push isolation into the database with row level security, so the rule is enforced no matter how the query is written.
-- Postgres row level security: a tenant can only see its own rows
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON invoices
USING (tenant_id = current_setting('app.tenant_id')::uuid)
WITH CHECK (tenant_id = current_setting('app.tenant_id')::uuid);
-- The app sets the tenant for the connection on each request
SET app.tenant_id = '2f9a...';
The USING clause filters what a tenant can read. The WITH CHECK clause stops a tenant writing rows that belong to someone else. Set the tenant id once per request from a trusted source such as the signed session, never from user input. This turns isolation from a coding habit into a hard database guarantee.
Tenant context and routing
Every request needs to know which tenant it belongs to before it touches data. Common approaches are a subdomain (tenant.yourapp.com), a path prefix, or a claim inside the auth token. Resolve the tenant early in the request, load its settings, set the database context (the tenant id for row level security, or the right connection for a siloed tenant), and carry that context through the whole request. Get this layer wrong and isolation breaks no matter how good the database rules are.
The noisy neighbour problem
When tenants share resources, one heavy user can starve the rest. A tenant running a huge report can lock tables, exhaust the connection pool, or saturate CPU, and suddenly every other customer is slow. This is the noisy neighbour problem and it is the main risk of pooling. Mitigations include per tenant rate limits, fair use quotas, separate connection pools or read replicas for heavy tenants, and moving the biggest tenants to their own database. Measure usage per tenant so you can spot a noisy neighbour before customers complain.
Provisioning and onboarding
Adding a tenant should be one automated, repeatable action, not a manual checklist. Onboarding usually creates the tenant record, seeds default settings and roles, provisions storage (a row, a schema, or a whole database depending on the model), and sends the first admin their invite. Automate it from day one. Manual onboarding does not scale past a handful of customers and it is a common source of half configured, broken tenants.
Scaling and sharding
Pooled databases grow until a single instance is no longer enough. The natural way to scale a multi-tenant system is to shard by tenant: route each tenant to a specific database shard, keeping all of a tenant's data together. Because tenants are independent, this shards cleanly with little cross shard querying. Connection management matters too. Thousands of tenants on database per tenant can exhaust connections, so use a pooler such as PgBouncer and share connections carefully.
Security, compliance, and migrations
Isolation is also a compliance story. Enterprise and regulated buyers ask how their data is separated, where it lives, and who can reach it. Strong answers include row level security, encryption at rest with per tenant keys where required, audit logs scoped by tenant, and the option of a dedicated database for tenants who demand it. Standards like SOC 2 will ask for evidence of these controls.
Migrations are the hidden tax of multi-tenancy. In a pooled database a schema change runs once. In schema per tenant or database per tenant, the same change must fan out across every tenant, ideally in safe batches with the ability to roll back. Plan your migration tooling early, because it only gets harder as tenant count grows.
How to choose
- Early stage, many small tenants: start pooled with row level security. It is cheapest and fastest to ship.
- Enterprise or regulated tenants: offer a dedicated database for isolation and compliance.
- Mixed reality: run a hybrid. Pool the long tail, silo the heavy hitters.
The cost of building a SaaS depends heavily on this choice, so decide it on purpose. See our breakdown of what it costs to build a SaaS and our guide to building an MVP for the wider picture.
FAQ
What is multi-tenant architecture in SaaS?
It is a design where one running application and infrastructure serves many customers, called tenants, while keeping each tenant's data isolated. It is cheaper than running a separate copy per customer, but it requires careful isolation so no tenant can ever see another's data.
Is database per tenant better than a shared database?
Database per tenant gives the strongest isolation and performance but costs the most to run and maintain. A shared database with a tenant id is far cheaper and scales to many small tenants, but it leans on row level security to stay safe. Many teams use both: shared for most, dedicated for large or regulated tenants.
How do you stop one tenant from seeing another tenant's data?
Tag every row with a tenant id and enforce it with database row level security, so the filter applies even if application code forgets it. Set the tenant id per request from the trusted session, never from user input, and use the WITH CHECK clause to block cross tenant writes.
Working with Apex Logic
We design and build multi-tenant SaaS products with isolation and scaling planned from the first commit, so you do not pay for a rebuild later. See our services or tell us about your product for a fixed, fair quote.
References
AWS SaaS guidance and Microsoft Azure multitenancy guidance - tenancy models and isolation patterns.
PostgreSQL documentation - row level security policies.
Apex Logic project data (2024 to 2026) - multi-tenant SaaS builds.
Comments