ON THIS PAGE (7 SECTIONS)
- ✓Database-per-tenant isolates by construction and costs more to operate. A shared schema isolates only if every query is constrained.
- ✓The tenant comes from the authenticated caller, not from a field the caller can set.
- ✓Tests must show that tenant A cannot read tenant B, including through exports, search, and jobs.
- ✓A shared vector index is still a shared store. Tenant scope applies there too.
Two customers share one application and one database. A list endpoint forgets the tenant filter. The page shows another company’s orders. Nothing was hacked. The query did what it was written to do, and it was written against the whole table.
Sharing a store is reasonable when you will operate one schema and many small customers. It is the wrong default when a customer requires a hard boundary you can show an auditor without arguing about a WHERE clause. Pick the boundary on purpose. If you share, make a missing tenant predicate a bug the tests catch, not a mistake a customer finds.
Two shapes, and what each requires
| Shape | Isolation | What you must operate |
| Database or schema per tenant | A connection cannot see the other tenant | More instances, a routing layer, and a migration story for each |
| Shared tables with a tenant key | Only queries that include the key | A single schema, and a guarantee the key is always applied |
| Shared tables, tenant chosen by the client | None, if the client can change the key | Do not do this |
The tenant id on a request body is untrusted. Derive it from the authenticated identity and ignore a conflicting value. Jobs and exports use the same derivation. A nightly report that selects every row and splits them in memory will eventually attach the wrong file. Filter in the query. Validate at the Boundary applies here: the tenant is not a field the payload may set.
Illustrative scenario
This scenario is illustrative. A support tool stores tickets in one table. The session carries the tenant. The repository method requires a tenant argument and will not run without it. A test inserts two tickets and asserts that tenant A’s list does not contain tenant B’s id. Search uses the same argument. A later vector index of ticket text stores the tenant on each row and filters before similarity, not after. Filtering after retrieval is how one tenant’s text is ranked into another tenant’s answer. That is the same class of mistake as an unscoped SQL query, and it sits next to Permission Boundaries for Enterprise AI.
Checklist
- Choose shared schema or separate database, and write down why.
- Take the tenant from authentication, not from the body.
- Require the tenant in the data-access API so a caller cannot omit it.
- Test cross-tenant reads, including export, search, and background jobs.
- Include caches and indexes in that test. A cache key without the tenant is a shared cache.
- Log access with the tenant id so a leak can be traced.
Questions that usually come next
Is a tenant column enough for a regulated customer?
Sometimes a customer’s contract asks for a separate database or a separate account. A column will not satisfy that contract. Offer the stronger boundary when the requirement is physical separation, and keep the shared design for everyone else.
Do admin tools get to bypass the filter?
An operator path can query across tenants, on purpose, with a different role and an audit entry. It should not be the same code path with the filter commented out. Bypass is a privileged action, not a missing argument.
Direct answers
Is a tenant column enough for every customer?
It is enough when the agreement allows a shared store. A contract that requires a separate database is a different product boundary.
Can admin tools skip the tenant filter?
Only on a privileged path that is audited. Do not implement that by calling the normal query without a tenant.
References & Prior Art
Input Validation Cheat Sheet
OWASP Cheat Sheet Series • OWASP (2026)
Barath
Product EngineerBarath builds production internal tools, double-entry financial ledgers, audit trail integrity, and supervised engineering workflows at Vasiva.