spring-boot-multitenancy
Installation
SKILL.md
Spring Boot multi-tenancy
The three isolation strategies
| Strategy | Isolation | Operational cost | Connection pooling | Best for |
|---|---|---|---|---|
| Separate database per tenant | Strongest — physical separation, independent backup/restore, independent scaling per tenant | Highest — N databases to migrate, monitor, and back up | One pool per tenant, or a pool-per-tenant cache with eviction | Enterprise/regulated tenants needing contractual data isolation, or wildly different tenant sizes (one tenant's load shouldn't affect another's) |
| Schema-per-tenant (single database, one schema per tenant) | Strong — separate tables per tenant, shared DB instance | Moderate — one DB to run, but N schemas to migrate | One pool, switching schema per request via Connection.setSchema() |
Most B2B SaaS with a moderate, bounded tenant count (tens to low thousands) |
Discriminator column (single database, single schema, a tenant_id column on every table) |
Weakest — a missing WHERE tenant_id = ? is a cross-tenant data leak, not a connection error |
Lowest — one schema, one migration path | One pool, shared by all tenants | High tenant counts (thousands+) where per-tenant schemas/databases don't scale operationally |
None of these is universally "correct" — the choice trades isolation strength against operational cost, and that trade-off should be made explicitly against the project's actual tenant count and compliance requirements, not defaulted to whichever is easiest to demo first.
Tenant context resolution
Every request needs to resolve "which tenant is this" before touching the database — typically from a subdomain, an X-Tenant-ID header, or a claim in the authenticated JWT (see spring-boot-security for where JWT validation happens; resolve the tenant claim after that, not before, so an unauthenticated request can't spoof a tenant ID):