Build multi-tenant from day one, or pay for it twice
7 min read
Single-tenant is faster to ship and almost always the wrong call for a product that intends to sell to more than one company. The cost of the shortcut is not visible until the second customer arrives, and by then the data model has assumptions about “the” organisation baked into every query.
Where the pain actually lands
The migration is rarely blocked by the schema. Adding a tenant_id column is an afternoon. What takes months is everything downstream:
- Background jobs that were written without a tenant context
- Caches keyed on a user ID that is only unique within one tenant
- Exports, reports, and admin tooling that assume a single dataset
- Auth flows where a user belongs to exactly one account, forever
- Every integration credential stored globally rather than per tenant
The version that is cheap
Decide isolation strategy before the first migration runs. Shared schema with a tenant discriminator, schema-per-tenant, or database-per-tenant each have a defensible use case, and the choice is driven by compliance requirements and expected tenant count more than by engineering taste.
Then enforce it at the lowest layer you can. A row-level security policy or a repository layer that refuses to build a query without a tenant scope will catch the mistakes that code review will not.
What to do if you are already live
Do not attempt a big-bang migration. Introduce the tenant column, backfill it with a synthetic tenant for existing data, then move one subsystem at a time behind a flag. It is slower than a rewrite and considerably less likely to lose data.