TenantLayer documentation
Start with Getting started. Read Row-level security before you deploy anything.
| Guide | What it answers |
|---|---|
| Getting started | Adding the dependency and getting isolation in ten minutes |
| Row-level security | How isolation is actually enforced, and the three mistakes that quietly break it |
| Isolation strategies | Discriminator column vs RLS, and why you want both |
| Tenant resolution | Headers, subdomains, paths, JWT claims, and precedence |
| Securing resolution | Why a header alone is not enough, and how to close that |
| Context propagation | @Async, CompletableFuture, virtual threads, scheduled jobs, HTTP, Kafka |
| The tenant registry | Who your tenants are, and running work for each of them |
| Testing | Fixtures, assertions, and how to tell a real isolation test from a vacuous one |
| Context storage | ThreadLocal today, ScopedValue later |
| Configuration reference | Every property |
| Architecture | How the pieces fit together, and why the obvious alternatives are wrong |
| Adopting in an existing app | Getting there from a running system, without a flag day |
| Troubleshooting | It returns nothing · the policy is not applying · the tenant is null |
The one-paragraph version
Postgres already has row-level security. TenantLayer does not reinvent it — the database does the enforcing, which is exactly why it is trustworthy. What TenantLayer does is the wiring around it: getting the tenant onto the connection at the right moment, guaranteeing it is cleared when the connection returns to the pool, carrying it across every thread and network boundary in between, failing closed when it is absent, and giving you a test that proves all of that rather than a README that claims it.