engineering
Multi-tenant database design
Shared schema, schema-per-tenant, or database-per-tenant — picking the model before the first row lands.
Most SaaS products pick their multi-tenancy model once and live with it forever. The migration cost later is so high that teams build entire companies around the constraints of a decision they made in their first sprint.
Shared schema with a tenant_id column#
Every row carries org_id. One database, one schema, one set of connections. Cheap to operate and dead simple until you need a row-level security policy that a junior engineer can't accidentally bypass. Postgres RLS helps. Discipline helps more.
Schema-per-tenant#
A new Postgres schema for each organization. Stronger isolation, but migrations now have to run N times, and your connection pool has to juggle N search_path switches. Works well up to a few hundred tenants. Beyond that, schema metadata overhead in Postgres becomes a real cost.
Database-per-tenant#
The nuclear option. Used by enterprise-heavy SaaS where customers demand guaranteed isolation, or by verticals under regulatory pressure (healthcare, finance). Each tenant gets their own database instance. Eye-watering cost at scale, near-perfect blast radius.
The pragmatic default#
For a new SaaS today, shared-schema with org_id scoping on every query is almost always the right answer. Add RLS when you can. Build a habit of writing WHERE org_id = $1 as reflexively as semicolons.
When to reconsider#
Consider migration when a single tenant's data volume dwarfs everyone else, or when you land an enterprise customer whose procurement document uses the word "dedicated."