Need the #1 custom application developer in Brisbane?Click here →

Multi-Tenant Database Design

9 min read

Multi-tenancy is when one application instance serves multiple customers, each with separate data. Your SaaS product has customers (tenants). Each customer's data must be isolated—customer A can't see customer B's data. The database design determines how secure this isolation is.

Multi-Tenancy Patterns

Shared schema: all tenants in the same tables, differentiated by a tenant_id column. Simplest, cheapest. All data is in PostgreSQL, all queries are fast. Risk: a developer forgets the WHERE tenant_id = ? clause, exposing all tenants.

Schema per tenant: each tenant gets their own schema within the same database. Better isolation. Adds migration complexity—schema changes must be applied to every tenant's schema. More complex to query across tenants.

Database per tenant: fully separate databases for each customer. Maximum isolation. Extremely expensive operationally—backups, monitoring, and upgrades multiply. Used only for very large or high-compliance customers who demand it.

The Right Choice: Shared Schema with Row-Level Security

For most SaaS applications, shared schema is correct. Store a tenant_id in every table. Use PostgreSQL row-level security to enforce filtering at the database level.

With RLS, you can set a policy on the orders table: only return rows where tenant_id = current_setting('app.current_tenant_id'). Every query automatically filters. A developer can't forget the WHERE clause because the database enforces it.

Implementing Multi-Tenancy

Each request includes tenant context: a user belongs to a tenant. The application knows which tenant the user is accessing. Before querying the database, set the session variable: SET app.current_tenant_id = 123.

Define row-level security policies on every table. SELECT on orders checks the policy. The policy returns only rows matching the current_tenant_id. The database prevents any query from returning data outside the current tenant.

The Tenant ID Omission Bug

The #1 multi-tenancy failure is a developer writing a query without filtering by tenant. Accidentally exposing customer data to other customers. This is a critical security bug.

RLS prevents it. If a query doesn't filter by tenant_id, the RLS policy still applies. Every query checks the policy. You can't accidentally expose data if the database enforces isolation.

Testing Multi-Tenancy

Write tests that specifically attempt to access another tenant's data. These tests should always fail. If a test succeeds in accessing another tenant's data, you've found a critical bug.

Automated tests: log in as user in tenant A, attempt to query tenant B's data. The query should return no results. Run these tests for every endpoint and query.

Shared Index Problems

All tenants' data is in the same tables, so indexes are shared. This is efficient. A single index on (tenant_id, created_at) serves all tenants. You don't need to scale indexes with the number of tenants.

Billing and Isolation

Track usage per tenant: API calls, storage, computation. Separate billing models: some customers pay per user, some per API call. In a shared schema, you can compute these metrics from the shared tables.

Migration Strategies

If you start single-tenant and grow to multi-tenant, migrating is painful. It's easier to build multi-tenancy from the start. Add a tenant_id column to every table. Use RLS from day one. When you add customers, the foundation is ready.

Shared Schema Practical Considerations

Backup and recovery are simpler with shared schema—one database backup for all tenants. Schema-per-tenant and database-per-tenant require per-tenant backups.

Querying across tenants is easy with shared schema. With schema or database-per-tenant, cross-tenant queries are complex. For analytics across all customers, shared schema is more efficient.

When to Use Other Patterns

Use schema or database-per-tenant when tenants need complete isolation for compliance. A healthcare provider might require separate databases for HIPAA compliance. A financial services company might segregate by regulatory boundary.

For most applications, these are overkill and add unnecessary complexity.

Warning
Multi-tenancy security is critical. A data leakage bug is a critical security incident. Test rigorously. Use row-level security. Audit your data access patterns. If you're not confident in your multi-tenancy implementation, hire expertise to review it.
Tip
Design multi-tenancy into your schema from day one. Even if you start with one customer, building the tenant isolation foundation early prevents painful migration later. The effort is minimal if done upfront.