# Multi-Tenant SaaS Architecture: Patterns, Trade-offs and Pitfalls

> Multi-tenant SaaS serves many customers from one codebase while keeping their data isolated. The core decisions are how you separate tenant data (shared schema, schema per tenant or database per tenant), how you identify the tenant on every request, and how you operate migrations and noisy neighbours.

Multi-tenancy is the idea that one running application serves many customers, called tenants, while each tenant sees only its own data. It is the economic engine of SaaS: one deployment to patch, one pipeline to release, and infrastructure shared across customers. It is also the source of the most serious class of SaaS bug, one customer seeing another's data. This article lays out the main architectural choices and the details that decide whether they hold up.

## The three tenancy models

The first decision is where tenant data lives. There are three common models, and many products use a mix.

### Shared database, shared schema

All tenants share the same tables, and each row carries a tenant identifier. This is the cheapest to run and the simplest to migrate because there is one schema. The trade-off is that isolation is enforced entirely by your code and policies, and a single large tenant can affect others.

### Shared database, schema per tenant

Each tenant gets its own schema inside one database. Isolation is stronger and per-tenant restores are easier, but migrations must run once per schema, and thousands of schemas strain the database catalogue.

### Database per tenant

Each tenant has a dedicated database. This gives the strongest isolation, simple per-tenant backup and data residency, and the option to place a tenant on its own hardware. The cost is operational: many databases to migrate, monitor and pay for.

## How to choose

- Many small tenants, price sensitive: shared schema.

- Regulated customers or data residency requirements: database per tenant for those customers.

- Few large tenants with custom needs: database or schema per tenant.

A pragmatic approach is to design the data-access layer so the tenancy model is a deployment decision, not a code rewrite. Then you can start shared and move individual tenants to dedicated databases when a contract demands it.

## Identifying the tenant on every request

The tenant must be resolved early and carried through the whole request. Common sources are the subdomain, a path prefix, or a claim in the access token. Resolve it in middleware, store it in a request-scoped context, and make it impossible to run a query without it. The failure mode to design against is a background job or an admin tool that forgets to set the tenant and reads everything.

## Enforcing isolation centrally

Do not rely on developers remembering to add a tenant filter. Put it in one place. In an ORM this can be a global query filter that adds the tenant condition to every query for tenant-scoped entities. At the database level, row-level security policies can enforce the same rule even if application code is wrong.

- Mark which entities are tenant-scoped, and make that the default for new ones.

- Apply the filter in the data-access layer, and set the tenant on writes automatically.

- Add automated tests that log in as tenant A and try to read or modify tenant B's records by identifier.

- Review raw SQL and reporting queries, which bypass ORM filters.

## Migrations and releases

With a shared schema, a migration runs once. With schema or database per tenant it must run for every tenant, so build tooling that runs migrations in parallel with progress and failure reporting, and design migrations to be backwards compatible so old and new application versions can run during a rollout. Never assume all tenants are on the same version at the same instant.

## Noisy neighbours and fair usage

Shared resources mean one tenant can degrade others. Put per-tenant limits in place before you need them: request rate limits, background job quotas, query timeouts, and caps on export sizes. Track latency and resource use per tenant so you can see who is responsible when something slows down.

## Configuration, customisation and feature flags

Customers will ask for variation. Resist forking code per tenant. Model differences as configuration: settings, custom fields, workflow templates and feature flags stored per tenant. Keep a single codebase and make variation data, not branches.

## Identity, billing and the admin plane

Separate the control plane from the tenant plane. The control plane holds tenants, plans, subscriptions and usage; it has its own admin interface and access rules. Subscription billing, trials and plan limits should be enforced from this plane so that entitlements are checked consistently everywhere.

For identity, decide early whether users belong to one tenant or can belong to several, and plan for single sign-on, because larger customers will ask for it.

## Backup, restore and data export

Customers will ask to restore their data to a point in time, or to leave and take it with them. Shared schemas make single-tenant restore harder, so design tenant-level export and import from the beginning, and test restore procedures regularly. Deleting a tenant, including from backups within a stated retention window, should be a documented, tested process.

## Observability

Include the tenant identifier in logs, traces and metrics from the start. When a customer reports a problem, you want to filter by tenant in seconds. Also record audit events for sensitive actions such as permission changes and exports.

## Tenant-aware caching and background jobs

Caches and queues are where tenant isolation quietly breaks. A cache key that omits the tenant will happily serve one customer another's cached response. Make the tenant part of every cache key by construction, for example through a cache wrapper that prefixes the key from the request context, and never cache tenant-specific data under a global key.

Background jobs need the same care. When you enqueue a job, include the tenant identifier in the message, and make the worker establish the tenant context before it touches data. Add a guard that fails the job if no tenant is set, so a mistake appears as an error in a log, not as a data leak.

## Handling tenant onboarding and offboarding

Onboarding should be automated and repeatable: create the tenant record, provision storage or a database if the model needs it, seed default configuration, create the first administrator and send the invitation. Make each step idempotent so a failed run can be retried safely. Offboarding deserves equal attention. Define what happens to data after cancellation, how long it is retained, how a final export is delivered and how deletion is verified, including from backups within a documented window.

## Security testing for multi-tenancy

- Include cross-tenant access tests in the automated suite for every endpoint that accepts an identifier.

- Test with predictable identifiers, since sequential IDs make enumeration trivial; prefer unguessable identifiers for public references.

- Review file storage paths and signed URLs, which are a frequent source of leakage.

- Include tenant isolation in periodic penetration tests and tell the testers it is in scope.

## What we have learned building multi-tenant platforms

We run our own multi-tenant ERP, [FAREXA](/products/farexa), and have built a multi-tenant [eLearning platform](/projects/elearning-saas) for clients. The lessons repeat: centralise isolation, keep tenancy a deployment choice, automate migrations, and measure per tenant. If you are planning a SaaS product, our [SaaS product development](/services/saas-product-development) team can help you choose a model and prove it with a thin first release.

## FAQ

### Which tenancy model should a new SaaS start with?

Most start with a shared database and tenant identifier on every row because it is cheapest to operate, then offer isolated databases to customers who need them.

### How do you prevent one tenant seeing another's data?

Enforce the tenant filter centrally, for example in the data-access layer or with database row-level security, and cover it with automated tests that attempt cross-tenant access.

### What is the noisy neighbour problem?

One tenant's heavy usage degrading performance for others. Rate limits, quotas, query timeouts and per-tenant monitoring are the standard defences.

---
Source: https://invozeal.com/blog/multi-tenant-saas-architecture
