Multi-Tenant Architecture

Multi-tenant healthcare SaaS architecture: how clinic isolation works

Every healthcare SaaS founder hits this question eventually. One database per clinic, or one shared database with filters? Get it wrong and you either burn your infra budget or ship a bug that leaks Clinic A's patients into Clinic B's dashboard.

I built the multi-tenant architecture for Synectus Medico, a platform that runs personal injury clinics across the US from one shared codebase. This is what I'd tell a founder before they write a single line of tenant logic.

Discuss Your Architecture
// the core decision

Database-per-tenant vs shared database with row-level security

Most articles present this as a clean binary. It's more of a spectrum, and the right answer depends on how many tenants you expect and how fast onboarding needs to be.

Database-per-tenant

Each clinic gets a fully separate database. Isolation is close to bulletproof, but onboarding clinic 200 means running migrations across 200 databases and monitoring 200 connection pools. Cost and DevOps overhead grow linearly with customer count.

Schema-per-tenant

Each clinic gets its own Postgres schema within a shared instance. A genuine middle ground, better isolation than shared tables, less overhead than fully separate databases, but you still run migrations across N schemas.

Shared database with row-level security

Every clinic's data lives in the same tables with a tenant_id column. A single migration updates everyone. Isolation depends on every query filtering by tenant correctly, backed by a database-level enforcement layer.

I went with shared database for Medico. New clinics onboard in minutes, and the risk of a forgotten filter gets solved with a second layer.

// two enforcement layers

Subdomain routing and row-level security

Subdomain-based routing

Each clinic gets its own subdomain. Middleware reads the x-sub-domain header, resolves the clinic, and attaches its ID to the request before anything else runs. No subdomain, no data.

Row-level security

PostgreSQL row-level security policies back the application filter. Even if a bug skipped the tenant_id filter, the database itself refuses to return rows outside the session's tenant context.

I think of it like a seatbelt and an airbag. The application filter does most of the work most of the time. Row-level security is there for the one time something goes wrong.

// scaling

Scaling a multi-tenant healthcare platform

A few things that mattered in practice, not just in theory:

Connection pooling

A pooler (PgBouncer, RDS Proxy) sits in front of Postgres so connections get reused instead of each request opening a fresh one as tenant count grows.

Tenant-aware caching

Redis cache keys must include the tenant ID. Cache a value without it, and you'll serve Clinic A's data to Clinic B the first time both hit a warm cache.

Composite indexing

tenant_id needs to be the first column in composite indexes on every tenant-scoped table, or queries scan far more rows than they should as the dataset grows.

// super admin layer

Onboarding a new clinic without an engineering ticket

In Medico, bringing on a new clinic is a super admin flow: create the clinic record, assign the subdomain, set the initial admin user, pick which modules are active, and the clinic is live. No deploy, no migration. That's the actual payoff of doing multi-tenancy right, the hard architectural work happens once, and after that, growth is a form submission, not a sprint.

// config, not code forks

Per-clinic customization without forking the codebase

Some clinics want a different theme color, others don't use the SMS module, others run four facilities. Medico stores this as data, theme tokens, feature flags, session timeout values, not as forked source files. The moment you fork code for one client, you've created a second codebase to maintain forever.

// common mistakes

Mistakes I see in multi-tenant healthcare builds

Treating isolation as "phase two"

Building single-tenant first and planning to "add multi-tenancy later" almost always costs more than building it right from the start, once real production data and real queries assume a single implicit tenant.

Forgetting isolation in file storage

Document storage needs the same discipline as database rows. File paths should be namespaced by tenant, and access checked against the requesting user's tenant before generating any signed URL.

Skipping audit logs on cross-tenant admin actions

Super admin actions touching a specific clinic's data need logging with the same rigor as any other sensitive action, arguably more, because super admin access is broad by definition.

Not planning tenant offboarding

What happens when a clinic cancels? Data export, retention windows, and eventual deletion all need a defined process from day one, not figured out reactively.

Frequently asked questions

Multi-tenant architecture is cheap to get right at the start and expensive to fix later. If you haven't locked in your tenancy model yet, this is worth getting right before you write your first feature.

Request an Architecture Review