2026-06-24 · 4 MIN READ
Tenancy at the database line
Multi-tenant isolation belongs in the database, not the application. One forgotten WHERE clause should not be able to leak another org's data.

The dangerous way to build a multi-tenant app is the obvious way: stamp a tenant_id column on every table and add `WHERE tenant_id = ?` to every query. It works until the day someone writes a query that forgets the clause, and then one org is reading another org's roster. The check lives in application code, which means it lives in every developer's memory, which means it is one oversight away from a breach.
or9.space is the eighteen-surface guild platform I built for one org, generalized so any org can run it — one codebase, deployed once, every tenant walled off in its own slice of the data. The isolation is the product, so I moved the boundary down a layer. Tenants are separated by Postgres row-level security policies keyed on a per-request tenant context. The database itself refuses to return a row that does not belong to the current tenant. There is no application-layer check to forget, because the enforcement is not in the application.
A policy you cannot test is a policy you do not have. So the platform ships a row-level-security policy suite and a tenant-leak fuzzer that hammers the wall on every run — it sets a tenant context, asks for things that belong to a different tenant, and fails the build if a single row crosses the boundary. FreedomGuard runs on the platform as the proof tenant: the original org living inside the generalized system, which means the isolation is exercised by real data every day, not just by tests.
On top of the wall the feature surface is wide and flag-gated per org — forums, treasury, a versioned handbook with member sign-offs, fleet, tournaments, recruitment, project boards, direct messages, and more — so each org switches on only what it needs. It ships open-core: a free ad-supported tier, a paid hosted tier with a custom domain, and a self-hosted AGPL tier you run yourself. The whole thing is full-stack TypeScript — Next.js, React, Prisma over Postgres — with the security policies and migrations in the same language as the app, and around 773 tests covering isolation, authorization, features, and billing.
The lesson generalizes past this one platform. When a security property has to hold across an entire codebase, push it down to the lowest layer that can enforce it for everyone at once. An app-layer rule is a request every future query has to honor. A database policy is a guarantee none of them can break.
- 01or9.space Platform — project page
The multi-tenant SaaS: RLS isolation, flag-gated features, three tiers.
/projects/or9-space-platform
- 02
- 03Eighteen sections, one guild
Companion: the single-org platform this generalized from.
/blog/freedomguards-rebuild
- 04Postgres row-level security
The database feature the tenant wall is built on.
https://www.postgresql.org/docs/current/ddl-rowsecurity.html