PRODSovereign European BaaS platformOpen Dashboard →

Performance · 11 min read

Dedicated vs shared database: performance and isolation

Affane Daylami · Fondateur · May 31, 2026

Back to blog

A shared database does not mean that your data is mixed with that of another client. It means that your database runs on a Postgres server shared with other databases. So the real question is not “is my data isolated?” » but “are my resources?” ". CPU, memory, connections and disk throughput can degrade because of a noisy neighbor even when each tenant has its own database, its own table, its own policies.

This English text was generated automatically from the French original and has not been reviewed yet.

This article compares the most documented Postgres tenancy models (shared schema, per tenant base, dedicated cluster, also called database-per-tenant vs shared database), explains the noisy neighbormechanism, then details how Aurabase implements its own two-tier model, verified in the provisioner code. For the methodology we apply before publishing a performance figure, see our backend benchmark methodology.

If you are looking for the question of data leakage between two clients (RLS, policies, service_role), this is not the angle of this article: our RLS comparison and dedicated database by project covers this logical isolation in detail. Here, we are talking about physical resources: CPU, IO, connections, cache.

The essentials

  • A shared database is not necessarily a shared scheme: Aurabase gives each project its own Postgres database, even on its standard levels, by only sharing the cluster.
  • noisy neighbor degrades physical resources (CPU, IOPS, connections, autovacuum), not data confidentiality: RLS does not solve it, that is not its role.
  • The Aurabase provisioner routes to exactly two architectures, verified in the code: FullyDedicated (entire CNPG cluster reserved for a project, enterprise level) or SharedClusterDedicated (dedicated base on the organization's CNPG cluster, never shared with another organization).
  • An Aurabase fleet cluster has a default observed capacity threshold of 1000 bases per cluster, configurable, beyond which the recommendation is to migrate to a dedicated cluster.
  • The right choice depends on your real constraints (compliance, traffic predictability, budget), not on a reflex “dedicated is always better”.
#
The models

Three Postgres management models, from the most shared to the most isolated

Microsoft's official documentation on the architecture of multi-tenant SaaS applications distinguishes three tenancy models, generally called Silo (dedicated resources per tenant), Pool (fully shared resources) and Bridge (a mixture of the two, some isolated tenants, others shared). These three models apply directly to Postgres, at the schema, database or entire cluster level.

Concretely, for a Postgres backend, this gives three distinct architectures. The shared schema (a single base, a tenant_idcolumn, RLS policies which filter the rows) is the most common Pool model in multi-tenant guides: economical, but the border between two clients becomes an SQL expression evaluated table by table. The base per tenant on a shared cluster is an intermediate Bridge model: each tenant has its own Postgres base (a real CREATE DATABASEcommand), but several bases coexist on the same physical cluster, therefore sharing CPU, IO and connections. The cluster fully dedicated per tenant is the complete Silo model: completely isolated CPU, RAM and IO resources, generally reserved for tenants with high compliance or load issues.

ModelResource insulationStorage insulationOperational Effort
Shared schema (tenant_id + RLS)NoneNone (communal table)Minimal (1 base to operate)
Per tenant basis, shared clusterPartial (cluster CPU/IO)Total (own basis)Moderate (N bases, 1 cluster)
Fully dedicated cluster per tenantTotalTotalHigh (1 cluster per tenant)

Silo / Pool / Bridge terminology: official Microsoft documentation, multi-tenant SaaS architecture patterns (Azure Architecture Center).

The intermediate model, base per tenant on a shared cluster, is often absent from the guides which present the choice as binary between “a single base for everyone” and “one server per client”. However, this is the one Aurabase uses by default, detailed below.

The choice between these three models arises with every multi-tenant architecture decision, not just with a BaaS provider: a team that builds its own SaaS backend on managed Postgres (RDS, Cloud SQL, or a self-hosted instance) makes exactly the same arbitration, with the same contention mechanisms in play once several clients are placed on the same physical instance.

#
The mechanism

The noisy neighbor: what deteriorates when resources are shared

A noisy neighbor (noisy neighbor) is a tenant that consumes a disproportionate share of an infrastructure's shared resources, to the detriment of other tenants on the same server. The term comes from the public cloud, but applies directly to a shared Postgres cluster: one database can degrade the performance of others without ever touching their data.

Six mechanisms come up most often in production:

  • CPU contention: an expensive query (join without index, massive sort) consumes CPU cycles that the kernel shares between all active databases in the cluster.
  • IOPS contention: a backup, a VACUUM FULL or a massive import saturates the cluster's disk throughput, slowing down reads and writes to other databases.
  • Connection exhaustion: max_connections caps the number of active connections at the entire cluster level, not per base. A base that opens too much reduces the margin of others.
  • Autovacuum contention: autovacuum runs with a limited number of workers per cluster; a database with a high write rate can delay cleaning the tables of another database.
  • Cache eviction: shared_buffers is a single memory for the entire cluster; a database with a large working set can evict the cached pages of a smaller neighboring database.
  • Shared maintenance windows: backup, replica failover, or major upgrade apply to the entire cluster, not on a per-base basis.
Cluster shared with four projects versus cluster dedicated to a single projectOn the left, a shared CNPG cluster hosts four bases (Project A to D) which all converge towards the same pool of CPUs, IOPS and shared connections, therefore possible contention between them. On the right, a dedicated CNPG cluster hosts only one project, with CPU, IOPS and connections reserved, so no external contention possible.Shared clusterProject AProject BProject CProject DCPU · Shared IOPSshared connectionsPossible contention between A, B, C, DDedicated clusterYour projectCPU · Reserved IOPSreserved connectionsNo external restraint

Structural diagram, not a measurement result: no comparative performance figures published to date for these two topologies.

Connection budget is often the most visible symptom in production, even before latency. This is the detailed subject of our max_connections tuning guide and our comparison PgBouncer, Supavisor and PgCat.

A transaction mode pooler (PgBouncer, Supavisor, PgCat) mitigates connection exhaustion, but does not remove CPU or IOPS contention: it reuses existing server connections, it does not add additional CPU cores or disk throughput to the cluster. Our article on transaction pooling mode details what this mode actually changes, and what it doesn't change.

#
The limit

RLS isolates data, not resources

Row-Level Security solves a different problem: it prevents a query from reading or modifying the rows of another tenant, at the logical level. It reserves no CPU cycle, no connection slot, no disk throughput for a specific tenant.

Two tenants can have perfectly watertight RLS policies and degrade each other at the same time: the noisy neighbor is a problem of physical resources, not of access rights. Confusing the two leads to a false sense of operational security once EPIRB is in place.

Info

For logical isolation (RLS policies, service_role, border between projects on the security side), see our dedicated article: RLS and dedicated base per project, the choice of multi-tenant isolation from Aurabase. This article remains on the level of physical resources.

#
In the code

The Aurabase model, verified in code

The provisioner code (aura-provisioner) documents exactly two possible architectures for an active Postgres project, from a provisioning consolidation that the code refers to as Task 12: FullyDedicated and SharedClusterDedicated. Legacy schema-grained models have been removed from the provisioning path.

The enterprise level triggers FullyDedicated: an entire CNPG cluster, reserved for this single project. All other levels (free, pro, team) route to SharedClusterDedicated: a full-fledged Postgres project_<uuid> database, on the CNPG cluster of the project organization. It is therefore not a shared schema: even on a standard plan, your database is a complete Postgres database, not one line among others in a common table. What is shared is the cluster (CPU, RAM, disk, connections), not the base itself.

An organization's CNPG cluster is created when its first Postgres project is provisioned and never hosts a project from another organization, a design choice locked at the code level (org_cluster.rs, Postgres advisory lock by organization at creation). The only possible noisy neighbor on the shared Aurabase landing is therefore another project of your own organization, never that of a third-party client.

fleet.rsrust
/// Nominal capacity (number of project bases) of an organizational cluster.
/// Observability threshold: beyond this, direct the organization towards FullyDedicated.
/// Controllable via FLEET_CLUSTER_CAPACITY (default 1000, limited [1, 1_000_000]).
pub fn fleet_cluster_capacity() -> i32 {
    std::env::var("FLEET_CLUSTER_CAPACITY")
        .ok()
        .and_then(|v| v.parse::<i32>().ok())
        .filter(|n| (1..=1_000_000).contains(n))
        .unwrap_or(1000)
}
2
Possible architectures
FullyDedicated or SharedClusterDedicated, no others
1000
Bases/cluster (default)
Configurable, limited between 1 and 1,000,000
PG 16
Postgres version
Not yet PG 17 on tenant/fleet clusters

Aurabase managed PostgreSQL cluster architecture specifications.

This threshold of 1000 bases per cluster is not a hard limit: it is an observability benchmark that triggers a recommendation to migrate to FullyDedicated, not an automatic block. It no longer drives any placement decisions, only one cluster is now possible per organization.

Each cluster, dedicated or fleet, exposes a CNPG Pooler (PgBouncer) which absorbs part of the pressure on active connections, in both topologies. What this pooler actually changes for resource contention is detailed below.

The CPU/RAM sizing of a shared cluster is also not uniform between organizations: it derives from the level of the organization via a dedicated function (FleetSizing::from_org_plan, verified in org_cluster.rs), and not from a single size applied to all levels. An organization at the team level does not size its cluster in the same way as an organization at the free level.

These two architectures run on PostgreSQL 16, not version 17, verified in the Dockerfile of the CNPG image used in production. This choice of version has its own tuning implications, detailed in our Postgres 16 vs 17 vs 18 comparison.

#
The decision

When pooling is enough, when dedicated becomes necessary

Astuce

Pooling is not a cheap compromise. It corresponds to the traffic of the vast majority of projects in development, launch or moderate growth, where a dedicated cluster would be an additional cost without measurable benefit.

SignalShared is enoughDedicated recommended
Formal compliance on physical isolation (health, HR, public sector)NoYes
Predictable traffic, moderate peaksYes
Unpredictable and sustained peak loadRisk of restraintYes
Tight budget, product in validation phaseYes
Contract clause (DPA) requiring documented insulationNoYes

For projects subject to a contractual obligation for documented physical insulation, our DPA and compliance pages detail what each level covers.

The downside of the base-by-tenant model, highlighted by several schema migration management tools like Bytebase, is operational rather than technical: each migration must be applied and verified on each base, one by one, even when they coexist on the same cluster. A fully dedicated cluster does not eliminate this cost, it even adds it: one migration per cluster to monitor independently, rather than just one.

Resources specializing in multi-tenant software architecture, such as CodeOpinion, regularly present this intermediate approach (per tenant basis on shared infrastructure) as a reasonable compromise between the shared scheme and the fully dedicated cluster, rather than a binary choice between the two extremes.

Going from shared to dedicated does not require rewriting a schema or changing engines: in both cases, it is Postgres, with the same pg_dump / pg_restore chain as that described in our Supabase to Aurabase migration guide. Changing the level remains a toggle operation, not an application rewrite.

#
FAQs

Frequently asked questions

Can an Aurabase shared database be slowed down by a project from another company?+
No. The Aurabase shared CNPG cluster belongs to a single organization and never hosts a project from a third party organization, verified in the provisioner code (org_cluster.rs). The only possible noisy neighbor on this level is another project of your own organization.
Does Aurabase's shared tier use a shared schema with a tenant_id column?+
No. Each project receives its own Postgres database (<9>project_<uuid></9>), even on the free, pro and team levels. What is shared is the CNPG cluster (CPU, RAM, disk, connections), not the base itself or its diagram.
How do I know if my project needs a dedicated cluster?+
Three signals come up most often: a formal compliance requirement on the physical isolation of resources, sustained and unpredictable traffic that regularly saturates available connections, or a DPA-type contractual clause requiring documented isolation. Below these thresholds, pooling remains, in the majority of cases, economically more rational.
Is the threshold of 1000 bases per cluster a hard limit?+
No, it's an observability threshold, not an automatic technical block. It is configurable via the variable FLEET_CLUSTER_CAPACITY (default 1000, limited between 1 and 1,000,000) and is used to signal that an organization should be oriented towards a dedicated cluster.
Is EPIRB enough to prevent noisy neighbors?+
No. The RLS filters the rows visible by a query; it reserves neither CPU, nor IOPS, nor connections to a specific tenant. Two tenants with perfectly watertight RLS policies can still degrade each other if they share the same physical cluster. See our article on RLS and dedicated base per project for the logical isolation part.
Why does pooling cost less than a dedicated cluster?+
Because the fixed cost of a Postgres cluster (CPU, RAM, reserved storage, backups) is distributed among all the bases of the organization that occupy it, instead of being paid in full by a single project. A dedicated cluster remains billed even when the actual project load is low, which makes it a rational choice especially once a compliance or traffic signal justifies it, not before.
#
Conclusion

What to remember

Dedicated base and shared base do not conflict on data security: both models can correctly isolate one tenant from another at the logical level. They oppose each other on physical resources (CPU, IOPS, connections, cache, maintenance windows). It is this plan that defines a noisy neighbor, not a poorly written RLS policy.

The Aurabase model, verified in the provisioner code, retains by default an intermediate compromise: a dedicated Postgres database per project, on a shared cluster but strictly reserved for a single organization, with a fully dedicated cluster reserved for the business level. The right choice depends on your real constraints, not on a reflex where the dedicated would always be the best option.

READY TO DEPLOY?

Your backend in five minutes.

No credit card required · 500 MB free · 50,000 MAU