Spring Boot Spring Data with multi tenancy
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Multi-tenancy in Spring Boot and Spring Data is not one feature you switch on. It is an architectural choice about how tenant data is isolated and how the application selects the right database, schema, or row subset for each request.
The first decision is the tenancy model: database-per-tenant, schema-per-tenant, or shared tables with a tenant discriminator. That decision affects everything else, including security, migrations, and repository behavior.
Choose the Multi-Tenancy Model First
The three common models are:
- database per tenant
- schema per tenant
- shared tables with a tenant column
Database per tenant gives the strongest isolation but more operational overhead. Shared tables are simpler to operate but require careful filtering so one tenant never sees another tenant's data.
Spring Data repositories sit on top of that choice. They do not solve the isolation problem by themselves.
A Simple Tenant Context
Most Spring-based multi-tenant implementations start by storing the current tenant in request-scoped or thread-local context.
You would usually populate this from a request header, subdomain, token claim, or authenticated principal.
Database-Per-Tenant Routing
For database-per-tenant, a common pattern is an AbstractRoutingDataSource that selects a data source based on the current tenant.
Once the tenant ID is set in TenantContext, Spring routes repository access to the appropriate underlying data source.
This is one of the cleanest models for strong isolation because repositories can stay mostly normal while connection routing changes underneath.
Capturing the Tenant from the Request
A servlet filter is a simple place to set the tenant for each request.
That finally block matters. Forgetting to clear tenant context is one of the easiest ways to leak tenant state between requests in thread-pooled servers.
Shared-Table Multi-Tenancy Is Different
If all tenants share the same tables, data isolation depends on every query filtering by tenant ID. That can be done with Hibernate filters, specifications, or explicit query conditions.
This model is operationally cheaper but easier to get wrong. One missing predicate can turn into a cross-tenant data leak.
So the "simpler database design" often shifts complexity into query safety and testing.
Spring Data Repositories Still Need Tenant Awareness
Even if the repository interface looks ordinary, the tenant boundary must exist somewhere:
- in routed data sources
- in schema switching
- in ORM filters
- in explicit query predicates
Repositories alone do not make the application multi-tenant. They simply participate in whatever isolation strategy the persistence layer enforces.
Common Pitfalls
- Starting with Spring Data code before deciding the actual tenancy model.
- Using a thread-local tenant context and forgetting to clear it after the request.
- Assuming repository interfaces automatically enforce tenant isolation.
- Choosing shared-table multi-tenancy without strong safeguards against missing tenant filters.
- Underestimating operational tasks such as migrations, onboarding, and per-tenant observability.
Summary
- Multi-tenancy in Spring Boot and Spring Data starts with an architecture choice, not a repository annotation.
- The main models are database per tenant, schema per tenant, and shared tables with a discriminator.
- A tenant context plus routed data source is a common solution for database-per-tenant setups.
- Shared-table designs can work, but they require disciplined tenant filtering in every data path.
- Spring Data participates in the design, but it does not replace the need for a real tenant-isolation strategy.
Related reading
- Spring Boot version versus Spring Framework version?
- Spring Boot without the web server
- Spring Cache Cacheable - not working while calling from another method of the same bean
- Spring Cloud Kubernetes - Spring boot fails to start when config reload is enabled
- Spring Boot Spring Security Hierarchical Roles
- Spring Boot SpringBootServletInitializer is deprecated
- Spring Cloud Kubernetes Configuration Watcher with Notification Recipient Not Based on Secret Name
- Spring Cloud Kubernetes Spring Cloud Gateway Unable to find instance for k8s service

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.