SignalNest Labs
SaaS2 min read

Multi-tenant architecture: the decision you cannot undo

Shared database, schema per tenant, or database per tenant. The choice determines your cost per customer, your isolation guarantees, and what enterprise deals you can close.

Key takeaways

  • Shared schema is cheapest, schema per tenant is a middle position, database per tenant gives the strongest isolation.
  • Enforce isolation at the database layer with row-level security so a missing filter fails closed.
  • Regional data residency requirements favour architectures that can split tenants across deployments.
  • Start shared but design so one tenant can be moved to its own database without application changes.

Multi-tenancy is how one deployment serves many customers. There are three common patterns: a shared database with a tenant identifier on every row, a separate schema per tenant within one database, and a separate database per tenant. They differ in cost per customer, isolation strength and operational complexity, and the choice is difficult to reverse once you have customers.

The three patterns

  • Shared database, shared schema. Cheapest per tenant and simplest to operate. Isolation depends entirely on your query discipline, which means one missing filter is a cross-tenant data leak. Right for high-volume, lower-value customers.
  • Schema per tenant. Stronger isolation with moderate overhead. Migrations must run per schema, which becomes slow at scale. A reasonable middle position for business-to-business products with hundreds rather than thousands of tenants.
  • Database per tenant. Strongest isolation, easiest to satisfy a customer demanding their data be separate, and the most expensive to run. Often required for enterprise, regulated or public sector customers, and it also makes per-tenant residency straightforward.

The mistake that causes breaches

In a shared-schema design, tenant filtering enforced only in application code will eventually fail. Someone writes a query without the filter, a background job forgets it, or a new endpoint copies an old pattern incompletely. Enforce isolation at the database layer, using row-level security or an equivalent, so a missing filter fails closed rather than returning another customer's data. Then test it explicitly with a test that attempts cross-tenant access and asserts that it fails.

Residency changes the calculation regionally

Saudi and UAE customers, particularly in government, finance and healthcare, increasingly require that data remain in country. With local hyperscale regions now available this is practical, but it means running multiple deployments in different locations. A database-per-tenant or region-per-group architecture makes that straightforward, while a single shared database makes it close to impossible without a rewrite. If enterprise or public sector customers are in your plan, this consideration should influence the decision now rather than later.

A pragmatic default

For most new products, start with a shared database and shared schema, with isolation enforced at the database layer, and design so that a single tenant can be moved to its own database without changing application code. That means never assuming tenants share a connection, keeping tenant resolution in one place, and avoiding queries that join across tenants. You get the low cost now and the option to satisfy a large customer later, which is the position worth being in.

Enforce tenant isolation in the database, not in application code. One missing filter should fail closed.

Keep reading

Let's talk

Ready to send a stronger signal?

Tell us what you are building and where you want to be found. We reply within one business day with a clear next step.