Database per tenant
Each tenant gets their own database instance. Strongest isolation — a misconfigured query cannot leak data between tenants. Easiest to comply with data residency requirements.
Operational cost: high. Hundreds of tenant databases require automation for provisioning, backup, and schema migrations. Use for: high-value enterprise clients with strict compliance requirements.
Schema per tenant
All tenants share a database engine but each has their own schema (namespace). Intermediate isolation. Good option for PostgreSQL with Postgres schemas. Schema migrations run once per tenant — automatable but not trivial.
Row-level isolation (shared schema)
All tenants share tables. A tenant_id column on every table partitions the data. Every query must filter on tenant_id.
-- Row-level security in PostgreSQL
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON orders
USING (tenant_id = current_setting('app.current_tenant_id')::uuid);
Lowest operational overhead. Requires discipline — missing a tenant_id filter is a data leak. Use PostgreSQL Row-Level Security (RLS) to enforce it at the DB level.