Choosing a database architecture for a SaaS product sounds straightforward until you start asking about tenant isolation, backups, migrations, and what happens when one customer consumes most of your resources.
A shared database is easier to operate, but tenant isolation needs careful enforcement. Separate databases provide stronger logical separation, but now you have a growing collection of databases to provision, migrate, monitor, and recover.
Neither approach eliminates complexity. It changes where that complexity lives.
Instead of starting with the question, "Which architecture scales better?", I would start with something more practical:
What does this product need to guarantee to each customer, and what will it cost us to maintain those guarantees?
Let's work through that decision.
First, what are we actually choosing?
Consider a SaaS project-management application used by three companies: Acme, Northstar, and Orbit.
They use the same application, but each company has its own users, projects, and tasks. An employee at Acme must not be able to access Northstar's projects.
There are two common ways to organize the data.
Option 1: Shared database
All three companies use the same database and tables.
A simplified projects table might look like this:
| id | tenant_id | name |
|---|---|---|
| 101 | acme | Website Redesign |
| 102 | northstar | Mobile App |
| 103 | orbit | CRM Migration |
When Acme requests its projects, the application queries only rows belonging to Acme.
SELECT id, name
FROM projects
WHERE tenant_id = :current_tenant_id;This is straightforward, but the tenant_id condition is important.
Imagine an API endpoint that retrieves a project using only its ID:
SELECT *
FROM projects
WHERE id = :project_id;If authorization and tenant scoping aren't enforced elsewhere, a user could potentially access another company's project by requesting its ID.
This is one of the fundamental risks of a shared-database architecture.
In practice, tenant isolation shouldn't depend on developers remembering to add a WHERE condition everywhere. Tenant context should be established from trusted authentication information, enforced consistently, and tested across reads and writes.
For PostgreSQL, row-level security (RLS) (opens in a new tab) can provide an additional database-enforced boundary. But it still needs correct policies, privileges, and connection-context handling.
A few additional database design decisions matter here:
- Indexes should account for tenant-scoped access patterns, such as
(tenant_id, status)when queries justify it. - Uniqueness requirements should be considered per tenant. For example, two companies might legitimately use the same internal project reference.
- Relationships and authorization checks must prevent records from being linked across tenant boundaries.
The benefit is operational simplicity: one database, one shared schema, and generally lower infrastructure overhead per customer.
The cost is that tenant isolation becomes a concern throughout the application.
Option 2: Database per tenant
Now imagine the same application, but Acme, Northstar, and Orbit each have their own database.
The application receives a request, determines which tenant it belongs to, and establishes a connection to the corresponding database.
The application code can remain shared. We aren't necessarily deploying three copies of the application.
We also aren't necessarily running three database servers.
Several separate tenant databases might be hosted on the same database instance or managed resource pool.
The main advantage is stronger logical data separation.
Acme's project records aren't mixed with Northstar's records inside the same database.
However, the application must still select the correct database. A mistake in tenant resolution or connection management can create an isolation problem even with separate databases.
And a new operational responsibility appears: every tenant database needs to be provisioned, maintained, migrated, backed up, and monitored.
Database-per-tenant moves some complexity away from query-level isolation and into infrastructure and database lifecycle management.
The question I would ask first: Can we restore one customer?
Imagine Northstar accidentally deletes a large collection of project records.
Their administrator contacts support and asks:
"Can you restore our data to how it looked yesterday without affecting anyone else?"
This is where the database architecture starts to influence the support experience.
With a shared database, restoring the entire database would also affect Acme and Orbit. That's usually unacceptable.
A possible recovery process would be:
- Restore a backup to a separate temporary environment.
- Identify Northstar's records and their relationships.
- Recover the affected data without overwriting newer, valid changes.
- Check referential integrity and ensure no other tenant's data is affected.
The difficulty depends on the data model and recovery requirements.
With database-per-tenant, the recovery boundary is more convenient because Northstar's data is stored separately.
You may be able to restore that database independently.
That doesn't mean recovery is automatic. You still need a valid backup, an appropriate restore procedure, and a way to handle application writes while recovery takes place.
But the scope of the operation is usually easier to manage.
If individual tenant recovery is a contractual requirement, this can be a meaningful reason to prefer separate databases.
If the product primarily serves many small customers with simple recovery expectations, it may not justify the extra operational overhead.
What happens when one tenant becomes much larger?
Suppose our SaaS application starts with 40 small companies.
Most have a few thousand tasks and relatively light usage.
Then one customer imports several million historical records and starts running expensive reports throughout the day.
Now we're dealing with the noisy neighbor problem: one tenant's workload can affect other tenants sharing the same resources.
In a shared database, that workload might increase CPU usage, disk I/O, or database contention, affecting queries belonging to other customers.
Would separate databases solve this?
Not necessarily.
If those databases run on the same server or share a resource pool, their workloads can still compete for compute and I/O.
Separate databases make it easier to manage individual workloads and, depending on the platform, move demanding tenants onto dedicated resources.
But performance isolation depends on the hosting architecture, not simply the number of databases.
Before changing the tenancy model, it's worth investigating the actual bottleneck.
Perhaps an expensive query needs better indexing. Perhaps reporting should use a separate analytical workload. Perhaps a specific tenant needs resource limits or a different service tier.
Changing the entire database architecture is an expensive response to a problem that might have a smaller solution.
The operational cost becomes clearer as the product grows
Creating a separate database for ten tenants isn't especially intimidating.
Creating, migrating, monitoring, and recovering hundreds or thousands of databases is a different problem.
Consider a simple application update that adds a column to the projects table.
With one shared database, the migration normally runs against one schema.
With database-per-tenant, you need a reliable process to apply the migration across the tenant database fleet.
What happens if database 47 fails while the first 46 have succeeded?
Can the application safely serve tenants whose databases are on different schema versions?
Can you retry only the failed migrations?
How do you know every tenant has received the update?
These questions matter more than the mechanics of running a migration command.
A database-per-tenant architecture benefits from automated provisioning, migration orchestration, schema-version tracking, monitoring, and recovery procedures.
For a small engineering team, that operational responsibility may outweigh the benefits of stronger data separation.
For a product with strict tenant-level requirements, it may be a worthwhile investment.
Three SaaS products, three reasonable decisions
Let's look at three hypothetical scenarios.
Scenario A: A project-management SaaS for small agencies
The product has 60 customers.
Most customers use the same features. Their workloads are relatively small, and there are no contractual requirements for dedicated databases.
The engineering team has three developers.
My starting choice would be a shared database, provided the team can implement and test tenant isolation properly.
Why?
One schema simplifies ongoing development, new tenants are relatively inexpensive to onboard, and operational overhead stays manageable.
I would prioritize strict tenant-scoped access, database constraints, authorization tests, query performance, and a documented recovery process.
I would also avoid assuming that shared databases must remain the architecture forever.
Scenario B: An enterprise application with individual recovery requirements
This product serves a smaller number of organizations.
Each customer requires independently managed data recovery, and some require data to remain in a specific geographic region.
Database-per-tenant becomes more attractive.
Individual databases provide clearer recovery boundaries and can be placed in the required regions when the infrastructure supports that arrangement.
However, a separate database doesn't automatically establish regulatory compliance or data residency. Backups, replicas, logs, and connected services also need to meet the requirements.
Here, the additional operational work may be justified by customer obligations.
Scenario C: Hundreds of small customers and a few very large ones
Now consider a SaaS platform serving 800 customers.
Most are small, but five generate a substantial share of the database workload.
Should all 800 customers receive dedicated databases?
Should every customer continue sharing one database?
Neither extreme is necessarily ideal.
A hybrid architecture might place smaller customers in shared databases while allocating dedicated databases or resources to customers with unusual requirements.
This adds complexity: tenant routing, data migration, and different deployment configurations must all be managed.
But it can be a reasonable response to a customer base with significantly different workload and isolation needs.
The important point is that a tenancy model doesn't need to be an all-or-nothing decision for the lifetime of the product.
Five questions to answer before choosing
Before committing to an architecture, I'd want clear answers to five questions.
1. What level of isolation do customers actually require?
Is well-enforced logical isolation sufficient, or do contracts and risk requirements demand separate data resources?
2. What are the backup and recovery expectations?
Can restoring a customer involve application-level data recovery, or must the database be recoverable independently?
3. How different are tenant workloads?
Are most customers similar, or will a few need substantially more compute, storage, or customization?
4. Can the team operate the architecture reliably?
It's easy to underestimate the long-term cost of provisioning, migrations, monitoring, backups, and incident response.
5. What happens if we need to move a tenant later?
A useful design anticipates how tenants can be located, exported, migrated, and routed without making the application depend on a permanent physical database location.
These answers should drive the decision—not whichever architecture looks more sophisticated in a diagram.
A few things I'd design carefully either way
Regardless of the chosen model, some problems remain.
- Tenant identity: Every request needs a trustworthy tenant context. Authentication and authorization alone don't automatically guarantee tenant isolation.
- Background jobs: Queue workers need the correct tenant context. The fact that a job runs outside the original HTTP request shouldn't change which customer's data it can access.
- Caches and file storage: Tenant separation doesn't end at the relational database. Cache keys, stored files, and other shared resources need appropriate isolation.
- Observability: When performance deteriorates, it should be possible to determine whether the issue is system-wide or associated with a particular tenant.
- Recovery testing: A backup is useful only if the team can restore the required data correctly. Recovery procedures should be tested, not assumed to work.
These concerns are easy to overlook when architecture discussions focus exclusively on database tables.
My conclusion
For a new SaaS product with many similar, relatively small customers, I would seriously consider starting with a shared database.
It reduces operational overhead and can scale well when tenant isolation, queries, and infrastructure are designed properly.
I would lean toward database-per-tenant when stronger isolation boundaries, independent recovery, tenant-specific configuration, or customer obligations justify the cost.
And where customer requirements differ significantly, I'd evaluate a hybrid approach rather than force everyone into the same model.
The question isn't whether shared or separate databases are more advanced.
It's which complexity your product needs to accept—and whether your team can manage that complexity reliably.
For an implementation example using database-per-tenant isolation, see my Laravel Multi-Tenant SaaS Starter, a personal project with public source code.
The scenarios in this article are hypothetical. They illustrate architectural decisions and do not describe any commercial system or customer implementation.