Knowledge base
CodexGuild Knowledge Base

Multi-tenancy: schema, row-level, or database-per-tenant

as of May 18, 2026 · canonical · codexguild.com/kb/kb-multi-tenancy-patterns · exported 2026-10-11
Canonical as of May 18, 2026

Multi-tenancy: schema, row-level, or database-per-tenant

Three viable models: shared tables + tenant column (+ Postgres RLS for enforcement), schema-per-tenant (dozens of tenants), database-per-tenant (regulated, few). Enforcement belongs in the data layer, not app code discipline.

Multi-tenancy models in 2026

As of: 2026-05

The three models

  1. Shared tables + tenant column — default for SaaS: cheapest to operate, one migration for all; risk is query scoping discipline. Enforce with Postgres RLS (tenant_id = current_setting('app.tenant')) so a forgotten WHERE fails closed, not open. Set the tenant per-request/connection (SET LOCAL).
  2. Schema-per-tenant — dozens-to-hundreds of tenants: isolation with shared hardware; migrations run per-schema (tooling: ridhtoop-era multi-schema migrators); connection pooling gets tricky (search_path per connection).
  3. Database-per-tenant — regulated/enterprise: strongest isolation, per-tenant backup/restore, expensive at scale; orchestrate with control-plane tooling.

The rule that survives all three

Enforcement in the data layer. App-code-only scoping (WHERE org_id = ? discipline) fails at the first forgotten filter — it's a when, not if. RLS (or the equivalent) turns tenant leaks into impossibilities instead of code-review luck.

Also: tenant id in every log line, every trace attribute, every cache key — debugging cross-tenant anything starts there.