A modular, decoupled multitenancy extension for Quarkus
supporting HTTP tenant resolution, ORM integration, and future integrations.
Quarkus Multitenancy is a Quarkiverse extension that provides a generic tenant resolution API and reusable building blocks for Quarkus applications.
It abstracts tenant identification logic away from any specific technology and exposes a consistent TenantContext that can be injected by application code or reused by integrations such as HTTP and ORM.
- Quarkus already provides powerful building blocks such as OIDC multitenancy and Hibernate ORM multitenancy.
- Applications still often need a consistent way to resolve and propagate the current tenant.
- This extension provides a reusable tenant resolution layer across HTTP, ORM, and custom integrations.
- It is now maintained as a Quarkiverse extension.
π‘ Designed for REST microservices and backend modules, it can provide tenant resolution for HTTP requests, persistence, cache, messaging, or custom application layers.
Quarkus Multitenancy is an extension designed to standardize and simplify tenant resolution for Quarkus services. It provides a decoupled multi-layer architecture.
- A core runtime module that defines
TenantResolver,TenantContext, and tenant resolution contracts. - Independent HTTP, ORM, and deployment layers built on top of the core.
- Built-in support for tenant resolution from headers, cookies, JWT claims, and request paths.
This makes the extension modular, lightweight, and framework-friendly, so you can plug tenant resolution into HTTP requests, ORM integrations, or custom application code.
- Consistent tenant identification per request
- Pluggable resolvers: header, cookie, JWT claim, path, and custom resolvers
- Minimal boilerplate code
- Integration point for datasources, caches, identity providers, and other tenant-aware components
- Quarkiverse migration completed
- First preview release preparation in progress
| Module | Description | Docs |
|---|---|---|
| π§ Core Runtime | Defines TenantContext, TenantResolver, and tenant resolution contracts |
Read more β |
| βοΈ Core Deployment | Build-time Quarkus integration for core | Read more β |
| π HTTP Runtime | Resolves tenants from header, cookie, JWT claim, or path | Read more β |
| π§© HTTP Deployment | Registers HTTP tenant resolution support | Read more β |
| π§± ORM Runtime | Integrates tenant context with Hibernate ORM multitenancy use cases | Read more β |
| βοΈ ORM Deployment | Quarkus feature registration for ORM integration | Read more β |
| π§ͺ Demo App | PostgreSQL multi-tenant REST demo | Read more β |
The core foundation of the Quarkus Multitenancy extension.
It defines the base APIs used to resolve and propagate tenants across layers, from HTTP requests to ORM and custom application code.
This module provides:
- The
TenantContextβ a request-scoped CDI bean exposing the active tenant. - The
TenantResolverβ an interface for resolving tenant identifiers dynamically. - The
TenantResolutioncontract β a three-state result model:Resolved,NotApplicable, andRejected. - The
CompositeTenantResolverβ allows multiple resolvers such as header, JWT, cookie, or path to cooperate.
Using this module together with the HTTP and ORM runtimes, each incoming request can be associated with a resolved tenant identifier.
β
Each request can carry a tenant identifier, for example X-Tenant: tenant1.
β
The active tenant is exposed through TenantContext.
β
The ORM runtime can use the resolved tenant to route persistence operations.
β
Actual database isolation depends on how the application configures Hibernate ORM, datasources, schemas, or databases.
For example:
| Request | Header | Tenant Resolved |
|---|---|---|
GET /api/users |
X-Tenant: tenant1 |
tenant1 |
GET /api/users |
X-Tenant: tenant2 |
tenant2 |
This means the extension provides the tenant resolution layer. The application remains responsible for configuring the actual persistence isolation model.
To enable HTTP tenant resolution:
<dependency>
<groupId>io.quarkiverse.multitenancy</groupId>
<artifactId>quarkus-multitenancy-http</artifactId>
<version>${quarkus-multitenancy.version}</version>
</dependency>To enable ORM integration:
<dependency>
<groupId>io.quarkiverse.multitenancy</groupId>
<artifactId>quarkus-multitenancy-orm</artifactId>
<version>${quarkus-multitenancy.version}</version>
</dependency>Replace ${quarkus-multitenancy.version} with the latest released version once the first preview release is published.
import io.quarkiverse.multitenancy.core.runtime.context.TenantContext;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@Path("/tenant")
public class TenantResource {
@Inject
TenantContext tenantContext;
@GET
public String getTenant() {
return tenantContext.getTenantId().orElse("NO TENANT FOUND");
}
}When you send:
curl -H "X-Tenant: tenant1" http://localhost:8080/tenantOutput:
tenant1
| Layer | Module | Responsibility |
|---|---|---|
| HTTP Runtime | quarkus-multitenancy-http |
Resolves tenant per HTTP request |
| ORM Runtime | quarkus-multitenancy-orm |
Connects ORM layer to tenant context |
Together, they provide tenant-aware request handling and persistence integration in Quarkus.
The JWT strategy resolves the tenant from a claim in a verified bearer token.
Applications must configure SmallRye JWT or Quarkus OIDC before enabling the jwt strategy.
Example:
quarkus.multi-tenant.http.strategy=jwt
quarkus.multi-tenant.http.jwt-claim-name=tenant
mp.jwt.verify.publickey.location=publicKey.pem
mp.jwt.verify.publickey.algorithm=RS256
mp.jwt.verify.issuer=https://my-issuer.example.comOIDC can also be used as the verification source:
quarkus.oidc.auth-server-url=https://issuer.example.comNamed OIDC tenants are also supported:
quarkus.oidc.customer.auth-server-url=https://customer-issuer.example.comIf a bearer token is present but cannot be verified, or if the configured tenant claim is missing, non-string, or blank, the request is rejected with HTTP 401 and does not fall back to the default tenant.
Tenant resolution uses a three-state result contract:
| Outcome | Meaning |
|---|---|
Resolved |
A resolver successfully resolved a tenant identifier |
NotApplicable |
The resolver had no input to process, so the next strategy may be tried |
Rejected |
The resolver found invalid input and the request must be rejected |
This distinction is important for security.
For example, a missing bearer token can be NotApplicable, but a malformed or unverifiable bearer token is Rejected and must not silently fall back to defaultTenant.
mvn clean install
cd quarkus-multitenancy-demo
mvn quarkus:devTo test the demo, import the demo.postman_collection.json file into Postman.
[HTTP Request]
β
[HTTP TenantResolver] (header/JWT/cookie/path)
β
[TenantContext] (request-scoped)
β
[ORM / Application / Custom Integration]
π See the quarkus-multitenancy-demo README for full setup with Docker, PostgreSQL, Postman, and sample tenants.
Full documentation is available at:
https://docs.quarkiverse.io/quarkus-multitenancy/dev/
This project is licensed under the Apache License 2.0.