Multi-tenant system design: isolating customers
A SaaS serves many customers (tenants) from one system. The design question is how strongly to separate them.

A multi-tenant system serves many customers (tenants), such as companies, from the same running software. It is cheaper and simpler to operate than one deployment per customer, but you must make sure one tenant never sees or harms another.
Three data isolation models
| Model | How | Pros | Cons |
|---|---|---|---|
| Shared database, shared schema | every table has a tenant_id column |
cheapest, easiest to scale to many tenants | a bug can leak data across tenants; noisy neighbours |
| Schema per tenant | one database, a separate schema (set of tables) per tenant | better isolation, easier per-tenant changes | many schemas hurt migrations and tooling |
| Database per tenant | each tenant has its own database | strongest isolation, easy per-tenant backup, restore and data residency | costly, hard to manage at thousands of tenants |
A common pattern is a mix: small tenants share, large or regulated tenants get their own database.
Enforcing isolation
The scariest bug in multi-tenant systems is cross-tenant data access (it is a form of IDOR).
- Put the
tenant_idin every query, and derive it from the authenticated session, never from user input. - Use row-level security (for example PostgreSQL RLS): the database itself adds the tenant filter, so a forgotten
WHEREcannot leak data. - Include
tenant_idin cache keys, queue messages, file paths and search indexes. - Write automated tests that try to read another tenant's data and must fail.
- Check access to object storage and files per tenant.
Noisy neighbours
One heavy tenant can slow everyone down. Protect others with:
- Per-tenant rate limits and quotas (requests, storage, seats).
- Resource isolation for background jobs: separate queues or worker pools, fair scheduling.
- Query timeouts and limits on expensive reports.
- Moving a very large tenant to dedicated resources.
Operations
- Backup and restore per tenant. With a shared schema this is hard, so plan it (export by
tenant_id). - Migrations touch all tenants at once with shared schema, but must run N times with database per tenant.
- Data residency: some customers require data to stay in a country. Database or cluster per region helps.
- Deleting a tenant (right to erasure) must remove data everywhere, including backups, logs and caches.
- Per-tenant usage tracking for billing and for finding noisy tenants.
Customisation
Avoid per-tenant code branches. Use configuration and feature flags instead, or the system becomes impossible to maintain.
Takeaway: pick the isolation model by risk and scale, enforce the tenant filter in the database layer, and limit each tenant's resources.
System Design series, Part 5 (failure and security): 6 of 6. Previous: Zero trust architecture explained.


