Websites
Database per tenant vs a shared database: the trade offs
A database per tenant gives each customer the strongest separation and the simplest restore, at the highest cost and with migrations to run many times. A shared database is cheapest and simplest to change, but every query must filter by tenant correctly, forever; a schema per tenant with its own login role sits between the two.
Indunil Asanka · Co-founder
4 min read · Published
Choosing between a database per tenant and a shared database is a trade between isolation and cost. A separate database for each tenant gives the strongest separation, no noisy neighbours and an easy restore of one customer, but costs the most and multiplies every migration. A shared database is cheapest and easiest to change, but depends on every query and every policy being right. A schema per tenant with its own login role is the common middle ground.
AWS’s SaaS isolation guidance calls the two ends silo and pool. The table above sets out four approaches against five trade offs.
Shared tables with a tenant column
Every table carries a tenant id, and every query filters on it. In Postgres, row level security moves that filter into the database: policies decide which rows each role sees, and if a table has row security enabled and no policy, the default is to deny every row. Supabase builds its access model on exactly this.
The appeal is cost and simplicity. One database, one migration, one backup. The risk is that the boundary between customers is a rule you wrote, repeated on every table, and one mistake is a data leak. Roles with the BYPASSRLS attribute and superusers skip the rules entirely, and table owners normally do too, so the role your application connects as matters. AWS also notes that a pooled model always carries some chance of a noisy neighbour, one tenant’s heavy use slowing the rest.
A database per tenant
Each customer gets a database or a whole project of their own. AWS’s silo model describes the benefits: no noisy neighbour concerns and simple per tenant cost tracking, with real challenges to cost and agility. Restoring one customer to yesterday is easy. Running a migration means running it once per tenant and checking each one, and databases that miss a migration drift apart.
Cost is the main limit. On Supabase, each additional project adds its full compute cost, $10 a month for a Micro instance, on top of the plan. That is fine for a few large customers and heavy for thousands of small ones.
A schema per tenant, in between
Postgres schemas are namespaces inside one database. By default, users cannot access objects in schemas they do not own unless the owner grants USAGE on the schema. Give each tenant a schema and a login role that can reach only that schema, and the database itself refuses one tenant’s role access to another’s tables, before any row policy runs. Row level security still guards the rows inside each schema, for example one customer’s orders from another customer of the same tenant.
This keeps most of the cost of a shared server while adding a boundary a forgotten filter cannot cross. A single tenant can be dumped and restored on its own. The costs are operational: migrations run once per schema, and the server’s CPU and connections are still shared.
How OneCraft uses this for its sites
OneCraft writes websites and apps with an AI agent, and when a feature needs data the agent turns on a backend for that site. On every plan it is a schema of its own in OneCraft’s pool project, with a login role that can reach no other site. Alternatively, an owner on any plan can connect their own Supabase account, and the site gets a project of its own there: the database per tenant route, paid for by the owner.
Inside either, every table must have row level security, and before a generation step can finish the agent checks each new table as an anonymous visitor, as a signed in person and, where there is one, as an admin. Migrations and a schema file are written into the site’s own repository, so each site’s structure is known and travels with its code. The row level security page explains the policies, and the headless CMS or a site with its own database page compares this with keeping content elsewhere. What it costs to run is in what an AI written website costs to run, and what gets built is on the website with its own database page.
Choosing for your own product
- Start shared when tenants are many, small and alike, and you can test every policy.
- Use a schema per tenant when you want a database level boundary and per tenant restores without paying for a server each.
- Use a database per tenant when customers require separation by contract, run heavy workloads, or need their own backups and region.
- Mix them when a few large customers pay for a dedicated database and everyone else shares.
Whatever you pick, test access as each kind of user before you ship, not after a customer finds the gap.
| Approach | Isolation | Cost per tenant | Migrations | Noisy neighbours | Backup and restore of one tenant |
|---|---|---|---|---|---|
| Shared tables, tenant column | Rules on every table; one missed filter or policy exposes other tenants | Lowest: one database for all | Run once for everyone | Shared CPU, memory and connections | Hard: one tenant's rows must be picked out of a shared backup |
| Schema per tenant, one login role each | The database refuses access to other schemas by default; rules still guard rows inside | Low: one server, many schemas | Run once per schema | Shared server | Moderate: one schema can be dumped and restored on its own |
| Database or project per tenant | Strongest: separate databases, separate credentials | Highest: each one has its own compute | Run once per database, can drift | None between tenants | Simple: restore that database alone |
| Hybrid: pool by default, dedicated on request | Depends on the tier | Mixed | Two paths to keep in step | Only on the shared tier | Depends on the tier |
Questions people ask
Is a schema per tenant secure?
It adds a real boundary. In PostgreSQL, users cannot access objects in schemas they do not own unless the owner grants USAGE on the schema. Give each tenant its own login role that can reach only its schema, keep row level security on inside it, and avoid roles that bypass it.
How many schemas can one Postgres database hold?
There is no single number to aim for. Every schema adds its own tables, indexes and catalog entries, and every migration must run in each one. In practice operations set the limit: running and checking one migration across thousands of schemas takes planning, tooling and time.
What is a noisy neighbour?
A tenant whose heavy use slows everyone else on shared infrastructure, such as a big import or a busy sale hogging CPU or connections. AWS's isolation guidance notes that a pooled model always carries some chance of this, and that a dedicated model removes it.
Does row level security replace separate databases?
For many products it is enough: Postgres applies policies to every query, and with no policy at all it denies every row. It does not separate CPU, backups or credentials, and a role with BYPASSRLS ignores it. Separate databases remain the answer when a customer requires physical separation.
Which is cheapest for a small product?
Shared tables with a tenant column, by a wide margin, because one database serves everyone. A schema per tenant costs little more on the same server. A database or project per tenant multiplies compute, so on Supabase each extra project adds its own compute cost, $10 a month for a Micro.
Written by
Indunil Asanka · Co-founder
Builds the generation pipelines behind OneCraft: the slide, flyer and poster layout engines, the document grid and the render workers that turn a written brief into a finished file.
LinkedIn profileSources
Written and checked by the OneCraft team. Last checked .
Make your own website
Describe what you need and the generator writes and designs it, then you edit anything you like.
See what it can makeRead next
Social login vs email login: what 13 site plans chose
Offer email login as the base and add a social login such as Google when customers sign in on their own phones and come back often. Of 13 AI site and app plans, 8 planned both Google and email, 3 email only and 2 no sign in at all, and the 11 databases that were built carried the same choice.
How long should a business plan be?
A small business plan for a lender or partner runs about 8 to 10 pages; a plan for one part of the business, such as marketing or a launch, about 5. Across 23 finished plans measured here the median is 5 pages and 1,335 words, and the full business plan example is 9 pages with 10 numbered sections.
Why apps get rejected from the App Store, by the numbers
Most App Store rejections are about performance, not policy: in 2024 Apple cited its Performance guidelines 1,235,471 times among 1,931,400 rejected submissions, and says over 40% of unresolved issues come under guideline 2.1, App Completeness. Crashes, placeholder content and missing information sink far more apps than anything controversial.