Vibe Engines
YouTube

Vibe Engines is free, interactive AI engineering & system design — runs in your browser. Pick a learning path

System Design

Design Multi-Tenant Isolation

Step 1 / 9

Learn system design by building multi-tenant isolation step by step.

The numbers to beat1 placeto enforceautoscoped queries0forgotten filters

The whole design, in writing

Every step of the build above, written out: the problem each piece solves, the option that was taken and the ones that were not, the numbers, and how it fails in production.

The big idea

What is multi-tenant isolation?

You serve many customers (tenants) from one system to keep it efficient and cheap to operate. But each tenant’s data, performance, and configuration must be strictly separated — tenant A must never see tenant B’s data, and one customer’s bad day must not become everyone’s outage. One missing filter is a cross-tenant data leak, the worst kind of bug.

Inject a tenant context on every request, scope all data access to it, choose an isolation model matched to the customer’s trust needs, cap noisy neighbors with per-tenant quotas, encrypt with per-tenant keys, and prove it with a tenant-scoped audit. Many customers, one system, strictly separated.

Step 1 · The skeleton

Many customers, one system

The naive version: all tenants hit the same Gateway and read from the same shared store, with nothing distinguishing them. It’s efficient — and it’s a data breach waiting to happen, because any query could return any tenant’s rows.

Tenant Acustomer A usersTenant Bcustomer B usersAPI Gatewayauth + tenant context
New in this step: Tenant A, Tenant B, API Gateway.

Stand up a shared Gateway and store serving all tenants. This is the efficient core of multi-tenancy; every step from here adds the separation that makes sharing safe.

Why this piece earns its place

The thing this skeleton quietly decides is what a tenant actually is, and at this stage it looks like a label hanging off a user — one person, one customer, look it up at login and be done. That shortcut is right for almost every account you will ever have, which is exactly why it survives long enough to hurt. Real customers are not flat: an enterprise arrives with subsidiaries, a sandbox beside production, and people who legitimately sit in more than one of them — a consultant on two accounts, a support engineer who has to look at yours. So I would write the id down as a property of the request from the first day, even while the lookup behind it is still one-to-one. The request names the tenant it is acting in, and resolving it is then a membership check — is this user allowed here — rather than a lookup of the one tenant a person owns. Nothing downstream has to change shape the day somebody has two, because every key, index, audit row and cache entry was already keyed on the request’s tenant and not on the person. The second decision is the id itself: make it opaque and non-sequential, because a tenant id that looks guessable turns every endpoint into an enumeration test.

What the new pieces do

Tenant Aclient
Users belonging to one customer. They must only ever see customer A’s data — and never even be able to tell that customer B exists on the same system.
Tenant Bclient
A second customer sharing the same deployment. Isolation from tenant A must hold for data, performance, and configuration — one system, strictly separated worlds.
API Gatewaybackend
The single front door. Authenticates the user, resolves which tenant they belong to, and stamps that tenant id onto the request so nothing downstream has to guess.

Step 2 · Who is this?

Inject tenant context

If each piece of code has to remember to filter by the right customer, someone eventually forgets — and a single unscoped query leaks one tenant’s data to another. You can’t rely on discipline for something this catastrophic.

API Gatewayauth + tenant contextTenant Resolvercontext + policy
New in this step: Tenant Resolver.

A single query that forgets to filter by tenant leaks data across customers. How do you prevent that reliably?

  1. Review helps but humans miss things, and one missed filter is a breach. Isolation this critical can’t depend on everyone remembering on every query forever — it needs to be enforced automatically.

  2. Forking the app per tenant is a maintenance nightmare and still doesn’t stop a shared query from crossing tenants. The fix is a single system that carries and enforces tenant context automatically.

  3. Authenticate, resolve the tenant, and stamp the tenant id into a request context that the data layer applies to every query by default. Isolation is enforced centrally, so no individual query can forget it.

Add a Tenant Resolver: authenticate the user, map them to a tenant, and inject the tenant id into the request context. The data layer applies it to every query automatically, so isolation is enforced by the framework, not by each developer remembering.

Why this piece earns its place

Central enforcement fixes the request path and creates a new blind spot: everything that runs without a request. Background jobs, queue consumers, scheduled reports, data migrations, the analytics export, the internal admin tool — none of them arrive through the gateway, so none of them carry a tenant. That is the dangerous shape, because those are exactly the code paths that read and write in bulk. The defense is to make an absent tenant context a hard failure rather than an empty filter: if the data layer cannot find a tenant, it refuses the query instead of quietly scoping to nothing — or, far worse, to everything. Work that legitimately spans customers then has to ask for it, one tenant at a time where it can, through a named elevation recorded with whoever invoked it. The rule I want is that crossing a tenant boundary is always a deliberate, visible act, never the default a missing value falls back to.

  • 1 placeto enforce
  • autoscoped queries
  • 0forgotten filters

What the new pieces do

Tenant Resolverservice
Maps the authenticated user to a tenant and injects the tenant id into the request context — the thing every query and check downstream keys off of.

Back of the envelope

resolve tenant at the gateway
from the authenticated identity
inject tenant id into context
threaded through every call
data layer scopes by default
no query can forget the filter

Step 3 · Where does data live?

The isolation spectrum

A shared table filtered by tenant id is cheap and easy to operate, but one bug crosses tenants and a regulated customer may reject "your data sits in the same table as everyone else’s." Stronger isolation costs more to run. There’s no single right answer.

API GatewayApp TierTenant DataIsolation Model
New in this step: App Tier, Tenant Data, Isolation Model. · swipe to pan the diagram

How strongly should you isolate tenant data — shared table, schema-per-tenant, or database-per-tenant?

  1. DB-per-tenant is the strongest but the most expensive and operationally heavy — thousands of databases to migrate, back up, and monitor. It’s right for high-trust/regulated tenants, but overkill and unaffordable as a blanket default.

  2. It’s a spectrum. A shared table filtered by tenant id is cheapest and scales to many small tenants; a schema or database per tenant gives stronger separation for regulated or high-value customers. Match the model to each tenant’s trust and compliance needs.

  3. A shared table is efficient but the weakest isolation — one bug crosses tenants, and some regulated customers won’t accept co-mingled storage. It’s a fine default for many tenants, but not a universal answer.

Pick the Isolation Model per customer along a spectrum: a shared table filtered by tenant id (cheapest, most tenants), a schema per tenant (stronger, still shared DB), or a database per tenant (strongest, most operational cost). Match strength to the customer’s trust and compliance needs.

Why this piece earns its place

Choosing per customer means you do not run one system, you run three at once, and that cost lands on the team rather than on the diagram. Every schema change now has to apply to the shared table, to each tenant schema, and to each dedicated database — so a migration stops being one statement and becomes a fleet rollout that can half-succeed, leaving customers on different versions of the same product. What keeps that affordable is making the isolation model a routing decision rather than a branch in business logic: the app resolves a tenant to a connection and a scope from tenant metadata, and feature code is written once against that. The other thing to commit to early is the move between models. The first large deal will ask to be lifted out of the shared store into its own, and a path that has never been run is a rewrite under a deadline. Treat promotion as a supported, tested migration from the day the spectrum exists.

  • row · schema · dbspectrum
  • cost ↕ separationtradeoff
  • per-tenantchoice

What the new pieces do

App Tierservice
Shared application servers that serve all tenants — but every read and write is automatically scoped to the request’s tenant id, so logic can never cross tenants.
Tenant Datadata
The isolation spectrum: a shared table filtered by tenant id (cheapest), a schema per tenant, or a database per tenant (strongest). Chosen per the customer’s trust and compliance needs.
Isolation Modelservice
The chosen isolation strategy per customer — from a fully shared, tenant-filtered store to a dedicated silo. A dial between cost/efficiency and strength of separation.

Back of the envelope

shared table + tenant id
cheapest, scales to many tenants
schema per tenant
stronger, one DB to run
database per tenant
strongest, highest ops cost

Step 4 · The noisy neighbor

Per-tenant quotas

Data isolation isn’t enough. One tenant sends a flood of traffic or runs a monster query, consuming the shared app and database capacity — and every other tenant slows down or errors. Isolation has to cover performance, not just data.

API Gatewayauth + tenant contextApp Tiertenant-scopedPer-Tenant Quotarate + resource capsIsolation Modelshared → silo
New in this step: Per-Tenant Quota.

One tenant’s traffic spike degrades every other tenant on the shared infrastructure. How do you contain it?

  1. Cap each tenant’s request rate and resource use (connections, query cost) so one customer’s spike is throttled to its own budget instead of consuming the shared pool. The noisy neighbor is contained to its own lane.

  2. Auto-scaling helps globally but doesn’t stop one tenant from monopolizing capacity faster than you can add it, and it makes one customer’s abuse everyone’s cost. You need per-tenant limits, not just more capacity.

  3. You can’t rely on a customer to self-limit, and by the time you notice, others are already degraded. Fair sharing has to be enforced by the system with per-tenant quotas.

Add Per-Tenant Quotas: rate limits and resource caps applied at the gateway per tenant, so one customer’s spike is throttled to its own budget instead of draining the shared pool. Performance isolation, alongside data isolation.

Why this piece earns its place

The number itself is the hard part, and both directions hurt. Set it low and you throttle a paying customer during their own peak — a monthly import, a seasonal rush — and a rejected request is an outage they will blame on you, not on their spike. Set it high enough that nobody ever reaches it and you have built a limit that never binds. Customer sizes in a SaaS are wildly skewed, so one global number is either useless for the largest tenant or lethal for it; I would derive each cap from that tenant’s own observed traffic plus headroom, and tie it to what they bought. I would also meter the expensive thing rather than the easy thing — one request can be a full-table report, so a request-rate limit measures the wrong resource. And a ceiling alone is not fairness: if the sum of everyone’s ceilings exceeds capacity, a small tenant can still be starved. Reserve a floor per tenant too, so being small is not the same as being last.

  • per-tenantrate limits
  • resourcecaps
  • nonoisy neighbor

What the new pieces do

Per-Tenant Quotacache
Enforces per-tenant rate limits and resource caps so one customer’s traffic spike can’t starve the shared app and database — the fix for noisy neighbors.

Back of the envelope

rate-limit per tenant
a spike hits only its own budget
cap resource use
connections, query cost, compute
fairness enforced
not left to good behavior

Step 5 · Separate secrets

Per-tenant keys + config

If every tenant’s data is encrypted under one shared key, a single key compromise exposes everyone, and you can’t cleanly delete or export one tenant. And tenants often need their own configuration — features, limits, branding.

Tenant Resolvercontext + policyApp Tiertenant-scopedTenant Datarow / schema / dbPer-Tenant Keyssecrets + config
New in this step: Per-Tenant Keys.

Give each tenant its own encryption key and its own configuration. Encrypting a tenant’s data under its own key means a key leak exposes only that tenant and enables true per-tenant deletion (drop the key). Per-tenant config lets one system behave differently for each customer.

Why this piece earns its place

Crypto-shredding rests on one assumption — that the tenant’s key is the only path to its plaintext — and that assumption breaks the day someone builds something useful out of the data. A search index, a cache, an exported report, a warehouse table behind a dashboard, an error log that captured a payload: each of those holds the customer’s content in the clear, and destroying the key does nothing to any of them. Deletion then reads as done, the certificate goes out, and copies remain. What makes the property real is an inventory — every derived store either holds no tenant content, or is encrypted under that same tenant key, or has its own deletion hook exercised by the same test that destroys the key. There is also a cost to notice now: the read path has acquired a dependency on a key service. Wrap a per-tenant data key rather than calling out on every read, or a slow key manager becomes a single customer’s outage that no aggregate error rate will show you.

What the new pieces do

Per-Tenant Keysdata
Each tenant’s own encryption key and configuration. Encrypting a tenant’s data under its own key means a leak of one key exposes only that tenant, and enables per-tenant deletion.

Back of the envelope

encrypt under a per-tenant key
a leak exposes one tenant, not all
crypto-shredding
destroy the key = delete the data
per-tenant config
features, limits, branding

Step 6 · Prove it holds

Audit + isolation testing

Isolation you can’t verify is isolation you can’t trust — and a regulated customer will demand evidence. Worse, a subtle bug could be leaking across tenants right now with no visible symptom.

App Tiertenant-scopedPer-Tenant Quotarate + resource capsTenant Datarow / schema / dbPer-Tenant Auditwho did what
New in this step: Per-Tenant Audit.

Add a tenant-scoped, immutable Audit trail of who accessed and changed what, per tenant — the evidence compliance requires. And test isolation continuously: automated checks that a tenant A token can never read tenant B data, run in CI. Isolation becomes provable, not assumed.

Why this piece earns its place

A cross-tenant test proves exactly what it enumerates, and leaks happen where nobody thought to write one — the endpoint added last week, the export job, a response cached under a key that forgot the tenant, an error message echoing another customer’s record id. A hand-maintained list drifts the moment the product grows. So I would generate the list instead of writing it: walk the route table at test time and fail the build on any route with no cross-tenant case attached, so a new endpoint is a failing test until someone shows that tenant A’s token cannot use it against tenant B. The audit trail deserves the same scepticism. A leak is a read, so a trail that records only writes cannot see the failure this whole page is about. And a log the app tier can rewrite is not evidence — it has to be append-only and outside the reach of the code it is watching, or all it proves is that nothing went wrong in a way that also broke the logging.

  • per-tenantaudit
  • immutabletrail
  • CIisolation tests

What the new pieces do

Per-Tenant Auditdata
An immutable, tenant-scoped audit trail of access and changes — required for compliance and the evidence that isolation is actually holding.

Back of the envelope

tenant-scoped audit log
who did what, per customer
immutable + exportable
compliance evidence
cross-tenant tests in CI
A’s token must never read B

You did it

You just designed multi-tenant isolation.

Tenant ATenant BAPI GatewayTenant ResolverApp TierPer-Tenant QuotaTenant DataPer-Tenant KeysPer-Tenant AuditIsolation Model
The finished design, end to end. · swipe to pan the diagram

Everything you assembled, in order

  • A shared gateway + store is the efficient core; the discipline is making sharing safe.
  • Resolve the tenant at the edge and inject a tenant id that scopes every query automatically.
  • Choose the isolation model per customer: shared+tenant-id, schema-per-tenant, or DB-per-tenant.
  • Per-tenant quotas isolate performance so a noisy neighbor can’t degrade everyone.
  • Per-tenant encryption keys bound a key compromise to one tenant and enable clean deletion.
  • A per-tenant audit trail plus automated cross-tenant tests make isolation provable.

Where an interviewer pokes next

Getting the boxes right is the easy half. These are the questions that separate a candidate who drew the diagram from one who has run the thing. Answer each one out loud before you open it.

  1. What’s the worst-case failure in a multi-tenant system?

    A cross-tenant data leak — one customer seeing another’s data — usually caused by a single query that forgot its tenant filter. It’s the worst case because it’s a data breach with legal and trust consequences, and it can be silent. That’s why tenant context is resolved once at the gateway and applied automatically by the data layer, rather than left to each developer to remember on every query: you remove the possibility of forgetting instead of relying on never forgetting.

  2. When should you use a database per tenant vs a shared table?

    It’s a spectrum driven by trust, compliance, scale, and cost. A shared table filtered by tenant id is cheapest and scales to thousands of small tenants — good for a self-serve SaaS. A schema per tenant adds separation while keeping one database to operate. A database per tenant is the strongest isolation and often required by regulated or high-value customers who won’t accept co-mingled storage — but it’s the most operationally expensive (many databases to migrate, back up, monitor). Many systems mix models: shared for the long tail, dedicated silos for enterprise tenants.

  3. What is the noisy-neighbor problem and how do you fix it?

    It’s when one tenant’s heavy usage — a traffic spike, an expensive query, a runaway job — consumes shared capacity and degrades every other tenant. Data isolation doesn’t help; this is performance isolation. The fix is per-tenant quotas: rate limits and resource caps enforced so each tenant can only draw on its own budget of requests, connections, and compute. Then one customer’s bad day is throttled to its own lane instead of becoming everyone’s outage. For strong cases you can go further and give heavy tenants dedicated compute.

  4. Why encrypt each tenant under its own key?

    To bound the blast radius of a key compromise and to enable clean per-tenant deletion. With one shared key, a single leak exposes every tenant’s data at once. With a key per tenant, a compromise is contained to that one customer. Per-tenant keys also enable crypto-shredding: to delete a tenant’s data (for a GDPR request or an offboarding) you can destroy its key, rendering the data unreadable even where copies linger in backups. It turns "delete all of a customer’s data everywhere" from a nearly-impossible task into destroying one key.

  5. How do you prove isolation actually holds?

    Two ways, together. First, a per-tenant immutable audit trail records who accessed and changed what, giving you evidence for compliance and a tripwire if something crosses tenants. Second, automated isolation tests run in CI that explicitly attempt cross-tenant access — a tenant A token trying to read tenant B’s data — and fail the build if any succeeds. This converts isolation from an assumption ("we’re careful") into a verified property checked on every deploy, which is exactly what a regulated customer’s security review wants to see.

Check yourself — the answers, and why

Seven steps in, these are the calls you should be able to make cold. Pick one, then read why.

  1. The reliable way to stop cross-tenant data leaks is to…

    Enforce isolation centrally so no individual query can forget its tenant filter.

  2. Isolating tenant data is a spectrum from…

    Match isolation strength to each customer’s trust and compliance needs.

  3. The noisy-neighbor problem is fixed by…

    Performance isolation: cap each tenant to its own budget so one spike can’t degrade all.

  4. Encrypting each tenant under its own key means…

    Per-tenant keys bound the blast radius and enable crypto-shredding for clean deletion.

  5. You prove isolation holds with…

    Audit gives evidence; CI tests that A’s token can never read B make it a verified property.

How you’d open this design in an interview

Before any boxes: agree what it must do, pin the qualities that shape everything, then build — naming each trade-off as you make it. The walkthrough above is that exact order.

What it must do

Agree on these before drawing a single box.

  • Serve many tenants: run one shared system for all customers while keeping their worlds strictly separate.
  • Scope every query: resolve the tenant at the edge and inject a tenant id that filters all data access automatically.
  • Isolate data: choose per customer along a spectrum — shared table, schema-per-tenant, or database-per-tenant.
  • Isolate performance: per-tenant rate limits and resource caps so a noisy neighbor stays in its own lane.
  • Separate secrets + prove it: a per-tenant encryption key and config, plus a tenant-scoped audit trail.

The qualities that shape everything

Each one names the mechanism that buys it.

Sharing infrastructure stays economical
One shared gateway, app tier, and store serve every tenant; separation is layered on top rather than forking the system per customer.
No query can ever forget its tenant filter
Resolve the tenant once at the gateway and inject a tenant id the data layer applies to every query by default — enforced centrally, not per-developer.
Match separation to each customer’s trust
An isolation spectrum — shared table by tenant id, schema per tenant, or database per tenant — chosen per the customer’s compliance needs.
One tenant’s spike can’t degrade the rest
Per-tenant quotas — rate limits and resource caps at the gateway — throttle a noisy neighbor to its own budget.
A key leak exposes only one tenant
Encrypt each tenant’s data under its own key, so a compromise is bounded to that customer and crypto-shredding makes deletion a key destroy.
Isolation is provable, not assumed
A tenant-scoped immutable audit trail plus automated cross-tenant access tests in CI that fail if A’s token can read B.

The trade-offs you say out loud

Senior signal isn’t the boxes — it’s naming what you gave up and why it was the right price.

Centrally injected tenant context over code-reviewing every query for a filter

Humans miss things and one missed filter is a breach. Resolve the tenant once at the edge and the framework scopes every query, so no individual query can forget it.

An isolation spectrum per customer over a database per tenant for everyone

DB-per-tenant is the strongest separation but the heaviest to run — thousands of databases to migrate and back up. Most tenants live happily on a shared, tenant-filtered store; reserve silos for regulated ones.

Per-tenant quotas over auto-scaling more servers on a spike

More capacity doesn’t stop one tenant monopolizing it faster than you can add it, and it makes one customer’s abuse everyone’s cost. Caps throttle the spike to its own budget instead.

A key per tenant over one shared encryption key

One shared key means a single leak exposes every tenant at once. A per-tenant key bounds a compromise to one customer and turns deletion into destroying a key (crypto-shredding).

Automated cross-tenant tests + audit over trusting that the code is careful

Isolation you can’t verify is isolation you can’t trust, and a subtle leak can be silent. CI tests that A’s token can never read B turn "we’re sure" into a property checked on every deploy.

The answer, out loud

What a strong answer to “Design Multi-Tenant Customer Isolation” sounds like, first question to last trade-off. It is about 6 minutes of talking; the whiteboard and the interviewer fill the rest of the 45. Read it aloud once, then close the page and give it yourself.

  1. 0–4 min

    What isolation actually promises

    I want to say what isolation means before I draw anything, because it is three promises and they fail in different ways. Data: a customer never sees another customer’s rows. Performance: one customer’s worst day is not everybody’s. Configuration: customers can differ without forking the product. We are sharing infrastructure because that is what makes this economical — a whole stack per customer is fine for ten and impossible for thousands. So the job is not to avoid sharing, it is to make sharing safe. And the data promise is the hard one, because it is the only failure that is silent, permanent and legally interesting.

  2. 4–9 min

    One shared stack, one front door

    The skeleton is a shared gateway in front of a shared app tier and a shared store. I draw it that way because what I care about first is that there is exactly one front door. Everything I add after this — context, quotas, keys, audit — is enforcement, and enforcement needs a chokepoint. If a large customer or an internal service can reach the app tier directly, or an analyst can open a replica by hand, then my rules hold on most paths, and most is not something you can claim to a security reviewer.

    Built in step 1: Many customers, one system
  3. 9–16 min

    Make forgetting unavailable

    Now the isolation itself. The version that fails is the one where every query is supposed to filter by customer and everyone is trusted to remember. Someone forgets once and that is a breach, so I do not want discipline, I want forgetting to be unavailable. The gateway authenticates the user, resolves the tenant the request is acting in, and puts that id into a context the data layer applies to every query unasked. The useful consequence is that code review stops being the control. The control is that scoping is implemented in one place, so a reviewer reads one thing carefully instead of everything hopefully.

    Built in step 2: Inject tenant context
  4. 16–24 min

    Where the data sits

    Where the data sits is a spectrum, and I would resist answering it once for everyone. A shared table keyed by tenant id is cheapest and carries the long tail. A schema per tenant gives visible separation with one database to operate. A database per tenant is the strongest and it multiplies backups, migrations and monitoring. I would default the long tail to shared and reserve silos for customers whose compliance actually demands it. What I want agreed in the room is that this is a commercial decision with an operational price — if a silo closes the deal, fine, but it should be sold, not given away.

    Built in step 3: The isolation spectrum
  5. 24–30 min

    The neighbor problem

    Data separation still leaves the failure customers actually feel: one tenant spikes and everyone else gets slow. Filtering does not help with that. I would put per-tenant rate limits and resource caps at the gateway, so a burst is throttled against that customer’s own budget instead of draining the shared pool. The tempting alternative is to scale up when it happens, and I would argue against it in the room: capacity arrives after the spike, it does not stop one customer taking whatever you added, and it turns one customer’s abuse into everyone’s bill. Adding servers answers growth. Quotas answer unfairness, and those are different problems.

    Built in step 4: Per-tenant quotas
  6. 30–36 min

    Keys and config per customer

    Then secrets. Under one shared key a single leak is every customer at once, so the blast radius of one mistake is the whole business. A key per tenant bounds it to one customer, and it buys the thing compliance always asks for: deleting a customer becomes destroying a key rather than hunting their rows through every system that ever touched them. I would keep per-tenant configuration beside the keys — features, limits, branding — because the alternative is per-customer branches in the product, which is how a shared system drifts back into one deployment per customer without anyone deciding to.

    Built in step 5: Per-tenant keys + config
  7. 36–42 min

    Evidence instead of confidence

    Last, proving any of it holds, because a leak can run for months with no symptom — no errors, green dashboards, and the first person to notice is a customer who saw a name they recognised. So, two things. A per-tenant audit trail of who read and changed what, which is both the compliance artefact and the tripwire. And tests that take tenant A’s credentials and deliberately try to read tenant B, run on every deploy, failing the build the moment one succeeds. That turns we are careful, which is unfalsifiable, into a property that was checked this morning.

    Built in step 6: Audit + isolation testing
  8. 42–45 min

    Close on the trade-off

    So: one shared stack, tenant context injected at the edge, storage chosen per customer along a spectrum, quotas for performance isolation, a key and a config per tenant, and audit plus cross-tenant tests to prove it. The whole design is one trade-off restated at every step — separation costs efficiency or operational load, and the skill is spending that where a customer’s trust needs it rather than everywhere. With more time I would work on per-tenant observability, so I can say whether something is slow for everyone or only for this customer, and on what happens when one customer contractually wants to pin a release while everyone else moves on.

What this teaches

Learn system design by building multi-tenant isolation step by step. An interactive guide covering tenant context propagation, the data-isolation spectrum (row-level, schema-per-tenant, database-per-tenant), preventing noisy neighbors with per-tenant quotas, per-tenant secrets and encryption, and audit plus isolation testing — how a forward deployed engineer serves many customers from one system without leaking data between them.

Key takeaways

  • A shared gateway + store is the efficient core; the discipline is making sharing safe.
  • Resolve the tenant at the edge and inject a tenant id that scopes every query automatically.
  • Choose the isolation model per customer: shared+tenant-id, schema-per-tenant, or DB-per-tenant.
  • Per-tenant quotas isolate performance so a noisy neighbor can’t degrade everyone.
  • Per-tenant encryption keys bound a key compromise to one tenant and enable clean deletion.
  • A per-tenant audit trail plus automated cross-tenant tests make isolation provable.

Concepts covered

  • What is multi-tenant isolation?
  • Many customers, one system
  • Inject tenant context
  • The isolation spectrum
  • Per-tenant quotas
  • Per-tenant keys + config
  • Audit + isolation testing
built so tenant A never sees tenant B, not memorized — inject context, isolate data, cap the noisy.
Finished this one? 0 / 65 System Designs done
NextDeploy an LLM in a Customer’s Environment Next in “Become a Forward Deployed Engineer” · step 41 of 63

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

More System Designs