100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace

Multi-Tenant Database Design Cheat Sheet

Multi-Tenant Database Design Cheat Sheet

Multi-tenant database architecture patterns covering shared-schema with tenant_id, schema-per-tenant, database-per-tenant, and RLS.

2 PagesAdvancedMay 12, 2026

Shared Schema with Row-Level Security

The most common pattern: one schema, a tenant_id column, enforced by Postgres RLS.

sql
CREATE TABLE invoices (    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),    tenant_id UUID NOT NULL,    amount NUMERIC NOT NULL,    created_at TIMESTAMPTZ DEFAULT now());CREATE INDEX ON invoices (tenant_id);ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;CREATE POLICY tenant_isolation ON invoices    USING (tenant_id = current_setting('app.current_tenant')::UUID);-- Set per-connection/session before running app queriesSET app.current_tenant = '3f2504e0-4f89-11d3-9a0c-0305e82c3301';

Schema-per-Tenant Provisioning

Stronger isolation via a dedicated schema, with shared connection pooling.

sql
-- Provisioning a new tenantCREATE SCHEMA tenant_acme;SET search_path TO tenant_acme;CREATE TABLE invoices (LIKE public.invoices_template INCLUDING ALL);-- Application connects and sets search_path per request-- e.g. in Node: await client.query('SET search_path TO tenant_acme');-- Migrations must be looped across all tenant schemas-- for schema in $(psql -tAc "SELECT nspname FROM pg_namespace WHERE nspname LIKE 'tenant_%'"); do#   psql -c "SET search_path TO $schema; \i migration.sql"# done

Application-Layer Tenant Scoping (Prisma middleware example)

Defense-in-depth: enforce tenant scoping in the ORM even when RLS is also in place.

typescript
prisma.$use(async (params, next) => {  const tenantId = getCurrentTenantId(); // from request context / AsyncLocalStorage  if (params.model === 'Invoice') {    if (params.action === 'findMany' || params.action === 'findFirst') {      params.args.where = { ...params.args.where, tenantId };    }    if (params.action === 'create') {      params.args.data.tenantId = tenantId;    }  }  return next(params);});

Isolation Models — Tradeoffs

The three standard multi-tenant data isolation strategies.

  • Shared schema + tenant_id- cheapest to operate, easiest to scale, weakest isolation; needs RLS or app-layer enforcement
  • Schema-per-tenant- stronger isolation, easier per-tenant backup/restore, but migrations and connection pooling get harder past hundreds of tenants
  • Database-per-tenant- strongest isolation and blast-radius containment, best for compliance-heavy tenants, but highest operational overhead
  • Row-Level Security (RLS)- Postgres feature that transparently filters rows by policy; defense-in-depth against a missed WHERE clause
  • Noisy neighbor- one tenant's load degrading others' performance; mitigated by resource quotas or moving big tenants to dedicated DBs
  • Tenant sharding- hybrid: group tenants across multiple shared-schema databases based on size/tier
Pro Tip

Enforce tenant isolation at two layers, not one — RLS policies in Postgres plus tenant scoping in your ORM/query layer — because a single forgotten `WHERE tenant_id = ?` in application code is the single most common cause of real-world cross-tenant data leaks.

Was this cheat sheet helpful?

Explore Topics

#MultiTenantDatabaseDesign#MultiTenantDatabaseDesignCheatSheet#Database#Advanced#Shared#Schema#Row#Level#Databases#CheatSheet#SkillVeris
Advertisement
Sri Hayavadhana Info-Tech

Professional Web Designing Services

  • Responsive Websites
  • E-commerce Solutions
  • SEO Friendly Design
  • Fast & Secure
  • Support & Maintenance
Get a Free Quote

Share this Cheat Sheet