Quarkus Multitenancy
Quarkus Multitenancy is a Quarkiverse extension that provides a reusable tenant resolution and context propagation foundation for Quarkus applications.
It standardizes how a tenant identifier is resolved from incoming requests and exposes the resolved tenant through a consistent TenantContext.
The extension is designed around a small set of abstractions:
-
TenantResolverfor resolving tenant identifiers from different sources. -
TenantContextfor exposing the resolved tenant during request processing. -
HTTP tenant resolution strategies such as header, cookie, JWT claim, and path-based resolution.
-
ORM integration for tenant-aware persistence use cases.
Why this extension exists
Quarkus already provides powerful building blocks for multitenancy, such as OIDC multitenancy and Hibernate ORM multitenancy.
This extension focuses on a different layer: resolving the tenant identifier consistently and making it available to the rest of the application through a shared context.
In other words, Quarkus Multitenancy does not replace OIDC multitenancy or Hibernate ORM multitenancy. It complements them by providing a reusable tenant resolution contract.
Quarkus multitenancy vs OIDC multitenancy
When developers search for Quarkus multitenancy, they often mean OIDC multitenancy, where different OIDC tenants or providers are selected depending on the request.
Quarkus Multitenancy targets a different concern.
It focuses on resolving the tenant identifier from request data such as headers, cookies, JWT claims, or path segments, and exposing that value through TenantContext.
OIDC multitenancy focuses on authentication provider selection.
Quarkus Multitenancy focuses on tenant id resolution and propagation.
The two concepts can be used together, but they solve different problems.
Quarkus multitenancy and Hibernate ORM
Hibernate ORM multitenancy focuses on database, schema, or datasource isolation.
Quarkus Multitenancy provides the tenant resolution layer that can feed tenant-aware persistence routing.
For example, a request can resolve the tenant from the X-Tenant header and expose it through TenantContext. ORM integration can then use that resolved tenant to support tenant-aware persistence use cases.
Installation
For HTTP tenant resolution:
<dependency>
<groupId>io.quarkiverse.multitenancy</groupId>
<artifactId>quarkus-multitenancy-http</artifactId>
<version>${quarkus-multitenancy.version}</version>
</dependency>
For ORM integration:
<dependency>
<groupId>io.quarkiverse.multitenancy</groupId>
<artifactId>quarkus-multitenancy-orm</artifactId>
<version>${quarkus-multitenancy.version}</version>
</dependency>
Quickstart
Enable HTTP tenant resolution and resolve the tenant from the X-Tenant header:
quarkus.multi-tenant.http.enabled=true
quarkus.multi-tenant.http.strategy=header
quarkus.multi-tenant.http.header-name=X-Tenant
quarkus.multi-tenant.http.default-tenant=public
Example request:
curl -H "X-Tenant: tenant1" http://localhost:8080/api/users/tenant
The current tenant will be resolved as tenant1.
Basic usage
By default, the HTTP module runs the strategy chain header,jwt,cookie. Each strategy is tried in order, and the first resolver that returns a value wins.
Example showing the default chain in action (header resolves first because the request supplies X-Tenant):
quarkus.multi-tenant.http.enabled=true
quarkus.multi-tenant.http.header-name=X-Tenant
quarkus.multi-tenant.http.default-tenant=public
A request with:
X-Tenant: acme
will resolve the current tenant as acme.
Accessing the current tenant
Application code can inject TenantContext to access the resolved tenant during request processing.
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import io.quarkiverse.multitenancy.core.runtime.context.TenantContext;
@Path("/tenant")
public class TenantResource {
@Inject
TenantContext tenantContext;
@GET
public String currentTenant() {
return tenantContext.getTenantId().orElse("public");
}
}
Resolution strategies
Cookie
quarkus.multi-tenant.http.strategy=cookie
quarkus.multi-tenant.http.cookie-name=tenant_cookie
Path
Path-based tenant resolution is useful for SaaS-style URLs where the tenant is part of the request path.
For example:
/t/acme/products
can resolve the tenant as acme.
Path-based resolution is opt-in. Enable it by adding path to the strategy list:
quarkus.multi-tenant.http.strategy=path,header,cookie
quarkus.multi-tenant.http.path-pattern=^/t/([^/]+)(?:/|$)
quarkus.multi-tenant.http.path-group=1
The path-pattern property defines the regular expression used to match the request path.
The path-group property defines which capturing group contains the tenant identifier.
With the default pattern:
^/t/([^/]+)(?:/|$)
the first capturing group extracts the tenant id from paths such as:
/t/acme
/t/acme/products
/t/customer-123/orders
This strategy does not rewrite the URL or perform request routing. It only extracts the tenant identifier and stores it in TenantContext.
Configuration
The HTTP module currently exposes configuration under:
quarkus.multi-tenant.http.*
Main options include:
| Property | Default | Description |
|---|---|---|
|
|
Enables or disables HTTP tenant resolution. |
|
|
Ordered list of built-in tenant resolution strategies. |
|
|
Header name used by the header resolver. |
|
|
JWT claim name used by the JWT resolver. |
|
|
Cookie name used by the cookie resolver. |
|
|
Tenant used when no resolver returns a value. |
|
|
Regex used by the path resolver. |
|
|
Capturing group used to extract the tenant from the path. |
ORM configuration
The ORM module integrates the resolved tenant with Quarkus Hibernate ORM multitenancy.
For database-based multitenancy, enable Hibernate ORM multitenancy and define one datasource per tenant:
quarkus.hibernate-orm.multitenant=DATABASE
quarkus.datasource.__bootstrap.db-kind=postgresql
quarkus.datasource.__bootstrap.jdbc.url=jdbc:postgresql://localhost:5433/postgres
quarkus.datasource.__bootstrap.username=user1
quarkus.datasource.__bootstrap.password=pass1
quarkus.datasource.tenant1.db-kind=postgresql
quarkus.datasource.tenant1.jdbc.url=jdbc:postgresql://localhost:5433/tenant1
quarkus.datasource.tenant1.username=user1
quarkus.datasource.tenant1.password=pass1
quarkus.datasource.tenant2.db-kind=postgresql
quarkus.datasource.tenant2.jdbc.url=jdbc:postgresql://localhost:5434/tenant2
quarkus.datasource.tenant2.username=user2
quarkus.datasource.tenant2.password=pass2
The ORM adapter uses the tenant id stored in TenantContext to resolve the current Hibernate ORM tenant.
The special __bootstrap tenant is used as the default/bootstrap tenant before a request tenant is available.
FAQ
Is this the same as OIDC multitenancy?
No.
OIDC multitenancy focuses on selecting authentication provider configuration.
Quarkus Multitenancy focuses on resolving and propagating the tenant identifier used by the application.
Does this replace Hibernate ORM multitenancy?
No.
It complements Hibernate ORM multitenancy by providing consistent tenant resolution input for persistence routing.
When should I use header, JWT, cookie, or path resolution?
Header-based resolution is useful for service-to-service or gateway-driven architectures.
JWT claim resolution is useful for authentication-centric flows where the tenant id is part of the token claims.
Cookie-based resolution is useful for browser applications.
Path-based resolution is useful for SaaS-style URLs such as /t/acme/products.