Every SaaS that sells to teams eventually faces the same question: how do we keep one customer's data from touching another's without duplicating the entire stack?
Three Models, Three Tradeoffs
Shared database, tenant column: cheapest and simplest, but one bug can leak across tenants. Schema per tenant: stronger isolation, harder migrations. Database per tenant: maximum isolation, highest operational cost. Most early-stage SaaS should start with a shared database and enforce tenant isolation at the query layer.
Enforce Isolation at the Lowest Layer
Do not rely on developers remembering to add `.Where(t => t.TenantId == ...)` to every query. Use an ORM global query filter, a middleware that sets the tenant context from the request, and row-level security in Postgres.
Plan for Migration Day
Your first tenant will not be your last. The biggest mistake is baking tenant assumptions into the schema. Keep tenant identifiers explicit, keep migrations reversible, and design the application so a tenant can be moved to its own database or schema without a rewrite.
StileTurn runs on a shared PostgreSQL database with row-level tenant isolation. It keeps operations simple while giving us a clean path to split large venues onto their own infrastructure later.