- by x32x01 ||
Imagine you build a gym management system.
The software becomes successful, and soon other gyms start asking to use it.
At first, you have:
The challenge is simple: Each gym must only see its own data.
So how should you design the system?
This is one of the most common software architecture interview questions, and understanding the answer is essential for anyone building modern SaaS applications.
For example:
But imagine having 1,000 customers.
Now ask yourself:
This is why modern SaaS platforms use a completely different approach.
In this model:
Every customer is called a Tenant.
This architecture powers many of the world's most successful SaaS products.
Example:
Imagine:
For this reason, Database Per Tenant is usually reserved for large enterprise customers.
All customers share:
Members
Immediately, a question appears: How do we know which customer owns each record?
The solution is simple.
Example:
Members
Payments table:
Payments
Subscriptions table:
Subscriptions
Now every record belongs to a specific tenant.
How does the application know if the request belongs to:
The application extracts:
and identifies the tenant.
After login:
Every request includes the token.
The server reads:
and automatically filters data.
You should always filter by tenant:
This ensures users only access their own records.
Developers can forget.
A better solution is using Global Query Filters.
The framework automatically adds:
to every query.
This dramatically reduces the risk of data leaks between customers.
A Members table might contain:
A simple index helps:
But many queries also search by email:
A composite index performs much better:
This dramatically reduces search time.
Instead of searching through 50 million rows, the database searches only the relevant partition.
Examples:
Example:
Sharding becomes necessary when a single database can no longer handle the workload.
instead of:
Suddenly one customer can view another customer's data.
This is one of the most dangerous SaaS security vulnerabilities.
Good:
Without tenant-aware cache keys, data leakage can occur.
But what happens when a job runs an hour later?
Always pass the tenant explicitly:
Bad:
Better:
Good:
The same email may exist in multiple organizations.
Otherwise troubleshooting production issues becomes extremely difficult.
The query suddenly consumes:
This is known as the Noisy Neighbor Problem.
It is one of the biggest reasons large customers eventually move to dedicated databases.
Example:
Each tenant has its own schema inside the same database.
✅ Cleaner organization
✅ Separate permissions
✅ Easier logical exports
Every migration, index, and schema change becomes more complicated.
Cross-tenant reporting also becomes significantly harder.
Shared Database + TenantId
Why?
A typical design includes:
Tenants
And nearly every business table contains:
(TenantId)
(TenantId, Email)
(TenantId, CreatedAt)
Start simple, design your tenant isolation carefully, implement proper indexing from day one, and only move to dedicated databases when business, legal, or performance requirements truly demand it. This approach allows your SaaS platform to scale from hundreds to thousands - or even millions - of users efficiently and securely. 🚀
The software becomes successful, and soon other gyms start asking to use it.
At first, you have:
- 100 gyms
- 500 gyms
- 1,000 gyms
The challenge is simple: Each gym must only see its own data.
So how should you design the system?
This is one of the most common software architecture interview questions, and understanding the answer is essential for anyone building modern SaaS applications.
The Naive Solution: One Application Per Customer ❌
The first idea many developers have is creating a separate application for every customer.For example:
- Gold Gym Application
- Power Gym Application
- Fit Zone Application
- Their own application
- Their own database
- Their own deployment
But imagine having 1,000 customers.
Now ask yourself:
- How many times will you deploy a bug fix?
- How many times will you release a new feature?
- How many databases will you monitor?
- How many backups will you manage?
This is why modern SaaS platforms use a completely different approach.
What Is Multi-Tenancy? 🏢
Multi-Tenancy is an architecture pattern where a single application serves multiple customers while keeping their data isolated.In this model:
- Gold Gym uses the system
- Power Gym uses the system
- Fit Zone uses the system
Every customer is called a Tenant.
This architecture powers many of the world's most successful SaaS products.
Multi-Tenant Database Strategies
There are three common approaches used in modern SaaS systems:- Database Per Tenant
- Shared Database
- Schema Per Tenant
Database Per Tenant Architecture 🗄️
In this design, every customer gets a completely separate database.Example:
Code:
GoldGym_DB
PowerGym_DB
FitZone_DB Advantages
✅ Strong data isolation
✅ Easier backup and restore operations
✅ Easier customer migration
✅ Reduced risk of accidental data exposure
Even if a developer writes an incorrect query, they can only access the current customer's database.Disadvantages
When your customer count grows, operations become challenging.Imagine:
- 1,000 tenants
- 1,000 databases
- Database migrations
- Backups
- Monitoring
- Performance management
For this reason, Database Per Tenant is usually reserved for large enterprise customers.
Shared Database Architecture 📊
This is the most popular approach in modern SaaS systems.All customers share:
- The same database
- The same tables
- The same application
Members
Code:
| Id | Name |
|----|-------|
| 1 | Ahmed |
| 2 | Omar |
| 3 | Sara | The solution is simple.
Using TenantId for Data Isolation 🔑
Most tables include a TenantId column.Example:
Members
Code:
| Id | Name | TenantId |
|----|-------|----------|
| 1 | Ahmed | 1 |
| 2 | Omar | 1 |
| 3 | Sara | 2 | Payments table:
Payments
Code:
| Id | Amount | TenantId |
|----|--------|----------|
| 1 | 500 | 1 |
| 2 | 700 | 2 | Subscriptions table:
Subscriptions
Code:
| Id | TenantId |
|----|----------|
| 1 | 1 |
| 2 | 2 | How Does the System Identify the Current Tenant? 🤔
When a request arrives:GET /membersHow does the application know if the request belongs to:
- Gold Gym
- Power Gym
- Fit Zone
Common Tenant Resolution Methods
Subdomains
Example:goldgym.system.comThe application extracts:
goldgymand identifies the tenant.
JWT Tokens
This is one of the most common approaches.After login:
Code:
{
"userId": 15,
"tenantId": 3,
"role": "Admin"
} The server reads:
tenantId = 3and automatically filters data.
Other Methods
You can also identify tenants using:- API Keys
- Custom Domains
- HTTP Headers
Filtering Data Correctly 🔍
Instead of querying data like this: SQL:
SELECT *
FROM Members SQL:
SELECT *
FROM Members
WHERE TenantId = 3 Global Query Filters Make Life Easier ⚙️
Writing tenant filters in every query is risky.Developers can forget.
A better solution is using Global Query Filters.
The framework automatically adds:
SQL:
WHERE TenantId = 3 This dramatically reduces the risk of data leaks between customers.
Scaling Challenges in Shared Databases 📈
Everything works great with:- 10 tenants
- 100 tenants
- 1,000 tenants?
- 10,000 tenants?
A Members table might contain:
- 50 million records
- 100 million records
- Or more
Indexing Is Essential for Multi-Tenant Systems ⚡
Most queries look like: SQL:
SELECT *
FROM Members
WHERE TenantId = 3 INDEX(TenantId)But many queries also search by email:
SQL:
SELECT *
FROM Members
WHERE TenantId = 3
AND Email = 'user@example.com' (TenantId, Email)This dramatically reduces search time.
Advanced Scaling Techniques
As the platform grows, additional strategies may be required.Partitioning
Split large tables into smaller partitions.Instead of searching through 50 million rows, the database searches only the relevant partition.
Archiving
Move old data into archive tables.Examples:
- Old subscriptions
- Historical payments
- Inactive records
Sharding
Distribute tenants across multiple databases.Example:
Code:
Tenants 1-1000 -> DB1
Tenants 1001-2000 -> DB2
Tenants 2001-3000 -> DB3 Common Multi-Tenant Security Mistakes 🚨
Forgetting the Tenant Filter
A developer writes: SQL:
SELECT *
FROM Members SQL:
SELECT *
FROM Members
WHERE TenantId = 3 This is one of the most dangerous SaaS security vulnerabilities.
Cache Isolation Problems
Bad: Code:
member:15 Code:
tenant:1:member:15 Background Jobs
A request knows the current TenantId.But what happens when a job runs an hour later?
Always pass the tenant explicitly:
Code:
GenerateInvoices(tenantId); File Storage Isolation
Avoid storing all files together.Bad:
Code:
/uploads/ Code:
/uploads/tenant-1/
/uploads/tenant-2/ Unique Constraints
Bad: Code:
UNIQUE(Email) Code:
UNIQUE(TenantId, Email) Logging
Always store TenantId inside logs.Otherwise troubleshooting production issues becomes extremely difficult.
Understanding the Noisy Neighbor Problem 🔊
Imagine one large tenant generates a massive report.The query suddenly consumes:
- CPU
- Memory
- Database connections
This is known as the Noisy Neighbor Problem.
It is one of the biggest reasons large customers eventually move to dedicated databases.
Schema Per Tenant: The Middle Ground ⚖️
Schema Per Tenant sits between Shared Database and Database Per Tenant.Example:
Code:
goldgym.Members
goldgym.Payments Code:
powergym.Members
powergym.Payments Benefits
✅ Better isolation✅ Cleaner organization
✅ Separate permissions
✅ Easier logical exports
Drawbacks
With:- 1,000 tenants
- 50 tables
50,000 tablesEvery migration, index, and schema change becomes more complicated.
Cross-tenant reporting also becomes significantly harder.
Which Multi-Tenant Strategy Should You Choose? 🎯
For approximately 95% of real-world SaaS applications, the best choice is:Shared Database + TenantId
Why?
✅ Lowest cost
✅ Simplest deployment
✅ Easier backups
✅ Easier monitoring
✅ Easier migrations
✅ Excellent reporting capabilities
✅ Supported by most modern frameworks
A typical design includes:
Tenants
Code:
| Id | Name |
|----|-----------|
| 1 | Gold Gym |
| 2 | Power Gym | And nearly every business table contains:
- TenantId
- Members
- Payments
- Orders
- Bookings
- Subscriptions
- JWT Claims
- Subdomains
- Global Query Filters
(TenantId)
(TenantId, Email)
(TenantId, CreatedAt)
Final Thoughts
Multi-Tenancy is one of the most important architectural concepts in modern SaaS development. While Database Per Tenant provides the strongest isolation and Schema Per Tenant offers a middle ground, Shared Database with TenantId remains the most practical solution for the vast majority of applications.Start simple, design your tenant isolation carefully, implement proper indexing from day one, and only move to dedicated databases when business, legal, or performance requirements truly demand it. This approach allows your SaaS platform to scale from hundreds to thousands - or even millions - of users efficiently and securely. 🚀