Multi-tenancy is an end-to-end ownership boundary
A tenant_id column is useful, but it is not a multi-tenant architecture. Tenant ownership has to survive every path through the product: authentication, authorization, database queries, background jobs, files, caches, analytics, billing, integrations, exports and audit. The system is safe only when tenant context cannot silently disappear between those layers.
Choose isolation based on risk and operations
| Model | Strength | Trade-off | Typical fit |
|---|---|---|---|
| Shared DB / shared schema | Efficient operations | Strong query discipline required | Most B2B SaaS |
| Shared DB / schema per tenant | More structural separation | Migration complexity grows | Smaller tenant counts / special requirements |
| Database per tenant | Strong infrastructure isolation | Provisioning, migrations and pooling cost | High-value or regulated tenants |
| Hybrid | Different tiers by risk | More platform complexity | Enterprise SaaS with isolation options |
Isolation is not a maturity ladder where database-per-tenant is always “better”. Select it against threat model, contractual requirements, scale, operational tooling and unit economics.
Resolve tenant context at the trust boundary
Derive current organization from authenticated membership, subdomain/session or another trusted mechanism. Do not authorize data access solely from an organization ID supplied in a request body. The server should prove that the actor belongs to the selected tenant before tenant-scoped services are created.
A useful design passes a typed tenant context through service boundaries so repositories and domain commands cannot run without it. This turns missing context into an implementation error rather than an invisible data-leak risk.
Propagate context through asynchronous work
Queues and schedulers are common leak points. A background job should include the tenant identity, resource identity and initiating actor/run where relevant, then revalidate current state at execution time. Do not rely on process-local “current tenant” state.
The same rule applies to webhooks. Map an external customer, subscription or installation back to an internal tenant using server-owned records before changing business state.
Database constraints should reinforce application boundaries
For shared tables, every tenant-owned record needs an unambiguous owner and indexes that start with or otherwise support tenant-scoped access patterns. Composite uniqueness often needs tenant ID as part of the key so one customer cannot reserve another tenant’s namespace.
PostgreSQL Row-Level Security can add defense in depth for selected tables. It is useful only if the connection/transaction reliably receives the intended tenant context and privileged roles are understood. RLS does not replace correct joins, ownership modelling or application authorization.
Plan migrations and provisioning as product capabilities
Schema changes affect every tenant. Migrations should be backwards compatible where rolling deployments are possible, observable and recoverable. Database/schema-per-tenant models also need orchestration for provisioning, version drift and failed upgrades.
Tenant creation itself is a workflow: organization record, default roles, billing customer, feature configuration, storage namespace and integration secrets may need to become ready atomically or through an explicit provisioning state.
Control noisy-neighbor risk
Isolation also concerns performance. Apply per-tenant quotas or scheduling where one customer can consume disproportionate queues, AI tokens, exports, storage or API calls. Include tenant identity in rate limiting and operational telemetry so capacity problems can be attributed and controlled.
Backups, exports and deletion must preserve tenant scope
A multi-tenant product eventually needs data export, account closure, legal retention or restoration. Design these paths early. An export should never rely on a UI filter as its isolation mechanism. Deletion should enumerate tenant-owned domains and integrations explicitly so orphaned data does not remain indefinitely.
First-party patterns from vertical SaaS
Softech uses these boundaries in multi-location operational software. Rentya separates facility/operator data, users, inventory and booking operations across a SaaS marketplace context, while TECHPRES.app connects customer locations, assets, field measurements and service workflows. The domain differs; the architectural requirement is the same: tenant context has to follow every operational record and action.
These patterns underpin our SaaS development and business systems work.
Tenant-isolation test matrix
- Read another tenant’s resource by guessed ID.
- Write a valid resource ID with the wrong organization context.
- Execute an old queued job after membership removal.
- Replay a webhook mapped to another external customer.
- Access cached data after switching organizations.
- Generate exports and reports with mixed tenant records.
- Restore or migrate one tenant without exposing another.
- Run privileged support operations and verify audit evidence.
