The Isolation Model
Isolate customers physically rather than by a column, and pay for it in operations.
Context
A platform serving multiple business customers, holding medical records, had to decide how customers are separated from one another. The obvious answer was row-level tenancy: one database, a tenant column on every table, one instance to operate. It is cheaper to run, much cheaper to deploy, and the default answer almost everywhere.
The question was not which is better in general. It was which failure mode is acceptable in this domain.
Decision
Isolate physically: one deployment per customer, with its own container, its own database and its own object-storage namespace. Tenancy still exists *inside* a deployment, because a customer has branches and staff, but isolation *between* customers is physical rather than logical.
Options Weighed
- Row-level tenancy, one database, a tenant column everywhereRejected
Cheaper to run and far cheaper to deploy. Rejected for a reason specific to this domain: a tenancy bug in a shared database exposes one customer's patient records to another. That is a category of failure that is unacceptable rather than merely bad, and no amount of careful query review fully eliminates it.
- Schema per customer within one databaseRejected
Reduces the blast radius without removing the class of failure, a query can still cross schemas, and the operational model still has a single database to lose.
- One deployment per customerChosen
Makes the failure structurally impossible rather than carefully avoided, and pays for that in operations rather than in code.
Consequences
- An entire class of cross-customer leak stopped being something to defend against and became something that cannot be expressed. That is worth a lot of operational overhead.
- Every customer is a separate deploy, a separate migration run, a separate backup and a separate set of credentials. Onboarding is an operational procedure, not a signup form.
- There is no cluster, no rolling deploy and no shared cache to hide behind. Several later designs follow from that rather than from preference: configuration lives in the repository because each container serves one customer, and the release process is gated by hand because there is no second replica.
- Storage keys carry a deployment namespace, so prefix isolation comes for free rather than being enforced.
- The identifier naming a deployment becomes immutable once it holds production data, because it is written into stored addresses. Renaming it later is a maintenance window, not a configuration edit.
- An unplanned dividend: the first customer to receive a release is a natural canary. Deploy to the most tolerant one, wait a day, then the rest, the staged-rollout capability that blue/green infrastructure exists to provide, obtained for free, and the reason that infrastructure has never been needed.
Cost of Not Deciding
The choice gets made implicitly by whichever schema is written first, and a tenant column appears on the first table because that is the path of least resistance. By the time the consequences become visible, in the release process, the configuration model, the key layout and the backup story, it is no longer one decision to revisit, it is all of them.
Rollback
Effectively none. Almost every later design is downstream of this choice, so reversing it is a rewrite rather than a migration. That asymmetry is exactly why it has to be made deliberately, early, and in writing.
Evidence Required to Reopen
- Customer count grows to where per-customer operational cost dominates engineering cost. The trade being made is operations for safety, and at some scale the numbers change.
- A regulatory or contractual requirement forces shared infrastructure.
- Not for running cost alone at small scale, the operational overhead was priced in when the decision was made, and re-raising it without new numbers is re-litigating a settled question.
Learned From
Derives From· 2
Related Knowledge· 3
Referenced By· 3
Version History
- v1.0.0
Accepted at the start of the project and never relitigated. Recorded here after the fact, once its downstream consequences were visible enough to describe.