Skip to content
scoi.io

Architecture · 2 min read

Multi-tenant isolation patterns we’d use again

Where to enforce the boundary, what to never trust the client for, and the tradeoffs at the query layer.

scoi.io · May 18, 2026

Layered navy rooms separated by electric-blue isolation walls

The first time a tenant sees another tenant’s row, you do not have a “permissions bug.” You have a product-ending event. We have now shipped this boundary on a legal corpus, an industrial IoT SaaS, and a workforce platform. The patterns that survived are unglamorous.

Enforce it before the handler gets cute

A middleware that requires a tenant claim is not enough if the query can still omit the filter. We treat tenant id as part of the primary key or as a mandatory predicate generated in one place — the repository — not in each route.

The client may send a tenant slug for routing. It may not choose the tenant for a query. If the session’s tenant and the requested resource disagree, that is a 404, not a 403 with a helpful body. Helpful bodies leak existence.

Don’t share the hot index

For Law4U, each firm’s vectors live in an isolated namespace. For IoThings, device telemetry is partitioned so a dashboard query cannot scan a neighbour’s fleet even if someone forgets a where. Shared tables with a column are fine at low stakes. They are not fine when the column is the only wall.

The tradeoff is operational: more indexes, more migrations, more “this tenant’s backfill is still running.” That cost is cheaper than a cross-tenant screenshot on LinkedIn.

Never trust the client for the boundary. Trust a claim you issued, then fail closed.

Query-layer habits

  • Default every list endpoint to the session tenant. No “admin override” without a second, audited actor.
  • Prefer composite unique keys that include tenant id, so a copied UUID from another workspace cannot collide into a write.
  • Log the tenant on every mutation. You will need it the day a support tool is pointed at the wrong workspace.
  • Test with two seeded tenants in CI, not one plus a comment that says “imagine another.”

We would use this again on anything that holds someone else’s documents, devices, or payroll. The throughline on this site is the same skill: make a messy input into a system other software can depend on. Isolation is how that system stays someone else’s.

← All insights

Building something in this neighbourhood?

A short note is enough. We’ll ask the right questions back.

Start a project