Skip to content

Multi-tenant

Multi-tenant architecture and data isolation

We design multi-tenant architecture in Postgres with Row-Level Security or schema isolation. Built so data is isolated, performance holds and you can migrate one tenant without touching the rest.

3D illustration of a single transparent glass tower with several internal floors separated by glowing orange dividers — symbolising strict tenant isolation in a single database.

Multi-tenancy designed correctly from the start

What we don't rebuild later

Postgres Row-Level Security as default
RLS
Per-tenant isolation where required
Schema
Provisioning, suspension, deletion as APIs
Lifecycle
SSO per tenant via WorkOS or Clerk
SAML

How we think about multi-tenancy

The kind of thing you only build wrong once.

Multi-tenancy is the kind of architecture decision you only build wrong once — because changing it later typically means touching every API, every query and every file system call in the entire codebase. We design multi-tenancy correctly from the start, based on how many tenants you expect, what isolation level your customers require, and what costs the least to maintain over the next five years.

Our default for most B2B SaaS is Postgres with Row-Level Security (RLS): one database, one schema, but every row is tagged with a tenant_id and the database enforces that queries only see their own tenant's data. It scales from 10 to tens of thousands of tenants on the same database, has the lightest operations, and fails safely if the application forgets to filter. We've also set up schema isolation (one schema per tenant) when enterprise customers require physical separation, and dedicated databases when it's a regulatory requirement.

Just as important as data separation is the entire organisation model on top: can a user be in multiple tenants? Can a tenant invite users via SAML? How are roles handled per tenant? We design that with you from day one — because it drives the database, the auth layer and your entire admin UI.

What we deliver

Data isolation, lifecycle and SSO built correctly from the start.

Postgres RLS as default, schema isolation where required, SAML SSO per tenant.

  • Postgres RLS as the default

    Every table gets a tenant_id column and an RLS policy that filters per session variable. Even if the application forgets to filter in a query, the database returns only the current tenant's data. Security as default, not as discipline.

  • Schema isolation when needed

    For customers that require physical separation (typically larger enterprise or regulated industries) we use per-tenant schemas in the same database. Migrations are rolled out coordinated; pooler configuration handles schema switching.

  • Tenant lifecycle: provisioning, suspension, deletion

    Creating a new tenant is an API call — not a manual process. Suspension (freezes access but keeps data), reactivation and deletion (with grace period + verifiable data export) are built in from the start.

  • Organisations, users and roles

    Users can belong to multiple tenants and switch between them without re-login. Roles are defined per tenant (admin, member, billing, custom) with well-defined permissions. Audit log on sensitive actions per tenant.

  • Usage, quotas and per-tenant metrics

    Usage measured per tenant (API calls, storage, users, features) so you can both bill on usage and prevent one tenant from starving the others. Rate limiting and quotas enforced at the API layer.

  • Migration strategy that doesn't tip over

    Schema changes rolled out in backwards-compatible steps. Backfills run as background jobs that respect tenant boundaries. We can roll out changes to 1 tenant, then 10, then all — without big-bang deploys.

Before you commit

What you should consider first.

  • RLS, schema isolation or dedicated database?

    RLS is the default for most B2B SaaS — lightest operations and best scale. Schema isolation when enterprise customers require it; dedicated databases when it's a compliance requirement. Most SaaS end up with a mix: RLS for most tenants, dedicated setups for the largest customers. We design that from the start so you can have both in the same product.

  • Cross-tenant features (admin, support)

    Internally you need to see data across tenants — support needs to help a customer, finance needs to see usage. That needs to be designed in from the start: a separate 'super-admin' role that can explicitly see across tenants, with audit logs on every cross-tenant action. Not a back door; an explicit mechanism.

  • Performance when one tenant grows louder than others

    In an RLS database, one tenant's heavy queries can drag performance for everyone else. We design query budgets, statement timeouts, and — for the largest tenants — connection pools dedicated per tenant. If one customer grows massively, we can move them to dedicated infrastructure without touching the codebase.

  • GDPR: right to deletion and data export

    When a tenant closes their account, you need to be able to delete their data verifiably — not 'set to archived'. We design data ownership per tenant from the start so deletion is an operational action, not a months-long cleanup project. Export delivered as JSON + assets so the customer can migrate data out.

FAQ

What people usually ask.

  • How long does it take to set up multi-tenancy?

    If you build from scratch, it's embedded in the overall SaaS MVP and costs typically 1–2 weeks extra in the foundation phase. If you retrofit multi-tenancy onto an existing single-tenant codebase, we're typically looking at 6–12 weeks depending on codebase size — and that investment is only worth it if you're planning multiple customers, otherwise consider dedicated instances instead.

  • Should all tables use RLS?

    Yes, as a rule. All tables with tenant-owned data get a tenant_id column and an RLS policy. Global tables (configuration, system data, plan definitions) don't have RLS — but they're explicitly marked as global so no one mistakenly uses them for tenant data. It needs to be clear which tables belong where.

  • How do we test that isolation actually works?

    We write tests that intentionally try to read another tenant's data — and fail if they succeed. Those tests run in CI on every pull request. Plus a periodic audit where we run queries with the session variable set to a different tenant and verify nothing is returned. Security only tested in your head isn't tested.

  • Can we have some tenants on dedicated databases?

    Yes — and it's often the right model over time. We design from the start with a tenant routing table that maps tenant_id to a database connection string. Most tenants point to the shared RLS database; specific tenants can point to a dedicated instance. The application doesn't need to know which model a tenant is on.

  • What about Single Sign-On per tenant?

    We set up SAML SSO per tenant via WorkOS, Clerk Enterprise or Auth.js — so enterprise customers can use their own IdP (Okta, Entra, Google Workspace) to log in to their tenant. Just-in-time provisioning creates users automatically; SCIM removes them when they leave the IdP.

Ready to get started?

Let's have a no-pressure conversation.

We'll get back within one business day with concrete input — not a stock proposal.