Every SaaS product serves many customers from one codebase. The decision that shapes the rest of the architecture is how those customers' data is separated. Change it late and you are rewriting queries, migrations, backups and billing all at once.

There are three common models. None is universally right; each trades isolation against cost and operational effort.

The three tenancy models

Shared database, shared schema. Every table has a tenant identifier column, such as organization_id, and every query filters on it. One database, one set of migrations, one backup.

Shared database, schema per tenant. Each customer gets its own schema (or table prefix) inside one database server. Queries do not need a tenant filter, but migrations must run once per tenant.

Database per tenant. Each customer has a separate database. Isolation is strongest, but connection management, migrations, monitoring and backups multiply with every customer you sign.

How they compare

Shared schema Schema per tenant Database per tenant
Isolation Logical, enforced in code Stronger, enforced by schema Strongest, enforced by the database
Cost per tenant Lowest Low to medium Highest
Migrations Run once Run per tenant Run per tenant
Cross-tenant reporting Straightforward Harder Hardest
Per-tenant restore Hard Moderate Easy
Best fit Many small and mid-size tenants Moderate tenant counts Few large or regulated tenants

Why most products should start with a shared schema

For a new B2B product with many small customers, the shared-schema model is usually the right starting point. It is the cheapest to operate, the simplest to migrate, and makes platform-wide reporting easy.

Its risk is equally clear: isolation depends entirely on your code never forgetting the tenant filter. That risk is manageable if scoping is enforced by the framework rather than remembered by developers:

  • Resolve the tenant once per request, from a subdomain, a header or the authenticated user, and store it in request context.
  • Apply the filter automatically. In Laravel, a global scope on a base tenant model adds the organization_id condition to every query; other frameworks have equivalent query hooks.
  • Set the tenant on writes automatically, so new records can never be created without an owner.
  • Test for leaks explicitly. Write tests that authenticate as one tenant and try to read, update and delete another tenant's records by ID. These tests catch the mistakes that code review misses.

Our own school management platform uses this approach: a single database with organisation-level scoping, where each school group is a tenant and branches inside it keep their own data and permissions.

Hierarchies inside a tenant

Real customers are rarely flat. A school group has branches; a retailer has stores; an agency has client accounts. Model this hierarchy explicitly rather than treating each branch as a separate tenant:

  • The tenant is the paying organisation that owns billing and global settings.
  • Sub-units such as branches carry their own data boundary inside the tenant.
  • Roles and permissions are granted per sub-unit, so a branch administrator cannot see another branch unless given access.

Getting this right early avoids a painful migration when your first multi-location customer signs up.

Per-tenant configuration and feature flags

Tenants differ in the modules they pay for, their limits and their preferences. Keep this in data, not in code branches:

  • A plan record defines limits (users, storage, messages) and included features.
  • A tenant settings record stores preferences and enabled modules.
  • A single gate function — "can this tenant use this feature?" — is checked by both the API and the interface.

This keeps pricing changes a configuration task rather than a deployment.

Keeping your options open

Starting with a shared schema does not lock you in. A few habits keep the path to stronger isolation open:

  1. Route every database access through the tenant-aware layer, never raw connections scattered through the code.
  2. Avoid foreign keys and joins that cross tenant boundaries, except for genuinely global reference data.
  3. Make tenant data exportable, so a large customer can later be moved to a dedicated database.
  4. Keep audit logs of sensitive actions per tenant from day one.

A short decision checklist

  • Do customers contractually require physical separation of data? Consider database per tenant for those customers.
  • Will you have hundreds or thousands of small tenants? Start with a shared schema.
  • Do you need platform-wide analytics? A shared schema makes it far simpler.
  • Must you restore one customer's data without touching others? Plan per-tenant export and restore early, whichever model you choose.

The best tenancy model is the one your team can operate reliably today, with a clear path to stronger isolation for the customers who need it later.

  • SaaS
  • Architecture
  • Multi-tenancy
All articles

Have a system to build, fix or scale?

Tell us where you are and where you need to be. We reply with questions, an initial view on approach and a suggested next step.