Multi-tenancy means many customers share one application and one database, and they must never see each other’s data. You need it the moment a second company signs up. You do not need a microservice per customer. You need a tenant_id (or equivalent) on every row that matters, enforced on the server, preferably also in the database.
The three models, in English
Shared database, shared schema. One Postgres, a tenant column, row-level security. This is the default. It is what we ship. It scales past 10,000 tenants if you index and you do not do silly queries.
Shared database, schema per tenant. Sounds tidy. Becomes a migration nightmare. Avoid it unless a compliance team is forcing you.
Database per tenant. Right for a handful of enterprise customers with contracts that demand it. Wrong for an MVP. You will spend your weeks on ops, not product.
What must be true on day one
- Every query that returns customer data is scoped to the current tenant. Not “usually.” Every query.
- The client cannot set the tenant. The session can.
- Auth knows about members and roles inside a tenant. A user can belong to more than one.
- Billing is per tenant, not per user, unless you are selling seats and you said so.
- File uploads, caches, and background jobs carry the tenant id too. The leak is often not in the table. It is in the queue.
Postgres row-level security
RLS is a seatbelt. Your app should still filter. RLS is what saves you when someone forgets. If you are on Supabase, turn it on before the second customer. If you are not, still write the policies or an equivalent guard.
Billing and entitlements
Plans and usage limits belong to the tenant. Checking them in the React tree is not checking them. Check on the server on every gated action. Webhooks must be idempotent or you will double-grant.
When to ignore all of this
If you have one user, and that user is you, a single-tenant app is fine. Promote it to multi-tenant before you send the second invoice, not after the third support ticket about “I can see Acme’s invoices.”
The stack we pair with this model, and the launch checks around it, are in the tech stack guide and the SaaS launch checklist. If you want an hour on your schema before you lock it, we do that.