Why We Built OmniFlow on Row-Level Security Instead of Schema-per-Tenant
Multi-tenant SaaS platforms typically pick between schema-per-tenant and a shared schema with a tenant_id column. Each has trade-offs — schema-per-tenant isolates blast radius but multiplies migration and connection-pooling overhead as you onboard more tenants.
OmniFlow uses a shared schema with tenant_id on every row, enforced twice: once at the application layer via a tenant-context interceptor, and again at the database layer using PostgreSQL Row-Level Security policies tied to a session GUC.
This defense-in-depth approach means a bug in application-layer scoping cannot leak another tenant's data — the database itself refuses to return rows outside the current tenant context, regardless of the query that asked for them.
It also means onboarding a new tenant is a single INSERT, not a new schema or a new set of migrations to run — a meaningful operational win as the platform scales to hundreds of tenants.