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.