Architecting Multi-Tenant SaaS Systems For Scale & Security
Key design patterns for database isolation, role-based access control (RBAC), and subscription metering in modern web software.
Alexander Wright
Managing Director & CEO

Key Takeaways
- Choose a tenancy model early; it shapes cost, security and migration effort.
- Enforce tenant isolation in the data layer, not only in application code.
- Model roles and permissions separately from users for flexible RBAC.
- Meter usage at the event level so billing stays accurate as you scale.
Multi-tenancy lets one application serve many customers while keeping their data separate. Done well, it lowers infrastructure cost and speeds up releases. Done poorly, it creates data leaks and painful migrations. These are the decisions that matter most.
Choosing a Tenancy Model
There are three common approaches, each balancing isolation against cost and operational complexity.
- Shared database, shared schema: every row carries a tenant identifier. Cheapest and simplest to scale, but isolation relies on discipline.
- Shared database, separate schemas: stronger separation with moderate overhead, useful for mid-sized customers.
- Separate database per tenant: maximum isolation and easy per-customer backup, at higher cost and operational load.
Rule of thumb
Start with a shared schema and a tenant_id on every table, and design so that high-value enterprise tenants can later be moved to dedicated databases.
Enforcing Tenant Isolation
Never trust every query to remember the tenant filter. Push enforcement down into the database with row-level security or a data-access layer that injects the tenant context automatically. Add automated tests that attempt cross-tenant reads and must fail.
-- PostgreSQL row-level security example
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON projects
USING (tenant_id = current_setting('app.tenant_id')::uuid);Role-Based Access Control
Keep users, roles and permissions as separate concepts. Users hold roles within a tenant, roles bundle permissions, and permissions describe actions on resources. This makes it simple to add custom roles for enterprise customers without changing code.
- 1Define permissions as verbs on resources, such as invoice.read or member.invite.
- 2Group permissions into roles like Owner, Admin, Member and Viewer.
- 3Scope role assignments to a tenant so one user can have different roles in different organizations.
- 4Check permissions on the server for every sensitive action.
Subscription Metering and Billing
Usage-based pricing needs trustworthy numbers. Record usage as immutable events, aggregate them per billing period, and sync totals to your payment provider. Keep plan limits in configuration so product and sales teams can adjust packages without a deploy.
“If you cannot explain an invoice line from raw events, your metering is not finished.”
Scaling and Observability
Watch for noisy neighbours: one heavy tenant slowing everyone else. Add per-tenant rate limits, query timeouts and dashboards that break metrics down by tenant. These signals tell you when it is time to shard or move a customer to dedicated resources.

