Tenant isolation

The cost of isolation grows with the tenant count. For 100 small tenants, a database for each tenant costs 210 USD/mo against 18 USD/mo for shared tables. Share the tables, and let the database filter each query by tenant.

Play a level

See it on the board

The same traffic runs on two boards. The simulator measured both when this page was built.

Board to show
HTTP/2SQLUsersLoad balanc…0.5 vCPU · 0.5 GBAPI server2 vCPU · 2 GBPostgres1 vCPU · 2 GB
HTTP/2HTTP/2SQLUsersLoad balan…API server2 vCPU · 2 GBPostgres1 vCPU · 2 GB
A schema for each tenant: misses a goal
HTTP/2SQLUsersLoad balanc…0.5 vCPU · 0.5 GBAPI server2 vCPU · 2 GBPostgres1 vCPU · 2 GB
HTTP/2HTTP/2SQLUsersLoad balan…API server2 vCPU · 2 GBPostgres1 vCPU · 2 GB
Shared tables, row rule by tenant: meets the goals
See it on the board
Measure Goal A schema for each tenant Shared tables, row rule by tenant
Error rate under 0.1% 60.1% Fail 0% Pass
p99 latency under 150 ms 27 ms Pass 27 ms Pass
Monthly cost 18 USD/mo 18 USD/mo

Key numbers

Default part values and prices from the catalog. The mini board has 100 small tenants and a budget of 80 USD/mo.
NumberValue
Connections a database accepts200 connections
Default pool size, one API server20 connections
One 2 vCPU, 4 GB server10 USD/mo
A reader with no tools stops page ordersTap or press Space to add or remove the reader

Separate reader · 0 of 100 attacks reach a tool

How it works

A service that holds the data of many customers must keep each customer's data apart. A bug that shows one tenant the rows of another is a serious breach. There are three common layouts, and each trades cost against isolation.

A database for each tenant gives the strongest wall. A bug in one tenant's code cannot reach another database. But each database has a cost, and 100 small tenants cost about 210 USD/mo here. Many databases are also hard to update and to watch.

A schema for each tenant puts the tenants in one server, with separate table sets. In the mini board this needs a connection pool for each schema, which comes to 500 connections. The database accepts 200, so connections fail.

Shared tables put all tenants in the same tables, with a tenant ID in every row. One server, one pool of 20 connections, 18 USD/mo. The risk moves to the code: a query without the tenant filter reads other tenants' rows. So do not trust each query to remember the filter. Enforce it in the database with a row rule that filters by the tenant of the session, so one bug cannot read the rows of another tenant.

In the mini board 100 small tenants send 2,000 requests/s, and the limit is 80 USD/mo. Only the shared layout fits.

In the levels you choose the layout from the number of tenants and the budget.