Skip to main content
Multi-tenancy allows a single deployment to serve multiple independent customers — called tenants — with complete data isolation between them. Each tenant operates as if they had their own dedicated environment, even though the underlying infrastructure is shared. In Lerian, multi-tenancy is available in SaaS (always active) and BYOC Multi-Tenant deployments.

Products that support multi-tenancy

The same JWT-based tenant model applies across the platform. Currently supported:
ProductMulti-tenant supportNotes
Midaz (Ledger + CRM)✅ YesOrganizations, ledgers, accounts, transactions, and balances are scoped to the tenant.
Tracer✅ YesRules, limits, validations, and audit events are scoped to the tenant. Each tenant has its own rule and limit catalog.
Reporter✅ YesReports run only over the calling tenant’s data.
Integrating any of these products is identical from the API perspective — the JWT carries the tenantId claim and the service resolves the tenant automatically.

How it works


Tenant isolation is enforced at the application layer through your authentication token.
  1. You authenticate via Access Manager and receive a JWT.
  2. That token includes a tenantId claim that identifies your tenant.
  3. On every API request, the platform resolves your tenant from the token automatically.
  4. All operations — creating organizations, querying ledgers, posting transactions — are scoped to your tenant.
You never pass a tenant identifier in headers or request bodies. The token handles it.
Multi-tenancy is transparent at the API level. Your integration code is the same whether you’re running single-tenant or multi-tenant — the only difference is that multi-tenant deployments require authentication on every request.

How tenant scoping looks in each product


The tenantId from the JWT scopes every resource the calling user can see or create. The resource model differs per product:

Midaz

A tenant is not the same as an organization. A single tenant can create and manage multiple organizations — for example, to represent subsidiaries, regional branches, or different business units.
Tenant (resolved from JWT)
├── Organization A
│   ├── Ledger 1
│   └── Ledger 2
├── Organization B
│   └── Ledger 3
When you list organizations, you only see the ones that belong to your tenant. The same applies to every Midaz resource — ledgers, accounts, transactions, and balances are all scoped to your tenant automatically.

Tracer

Tracer scopes its catalog directly under the tenant — there is no organization layer.
Tenant (resolved from JWT)
├── Rules
├── Limits
├── Validations
└── Audit events
When you list rules or limits, you only see entries created by your tenant. Validations execute against the tenant’s own rules and limits, never against another tenant’s. Audit events are likewise tenant-scoped — even hash-chain verification runs over the calling tenant’s chain only.

Other products

Reporter and the rest of the platform follow the same pattern: the tenant is the outermost scope, and the JWT is the only source of truth for which tenant the caller belongs to.

Data isolation


Tenant data is isolated at the database level. Each tenant operates on a separate database, meaning:
  • Data from different tenants is never stored together.
  • Queries from one tenant cannot reach another tenant’s data.
  • Even if two tenants create identical organization structures, their data remains completely separate.
This isolation is enforced by middleware that routes each request to the correct database or schema based on the tenantId claim in your JWT. Depending on the configured isolation mode, tenant data lives in a dedicated database (DATABASE mode) or a dedicated schema within a shared database (SCHEMA mode). There is no way to bypass this through the API.
BYOC operators can choose between database-level or schema-level isolation depending on their infrastructure requirements. See Isolation modes below.

Isolation modes


BYOC operators choose how strongly tenants are isolated at the storage layer. The choice is made per service, so different products — or even different tenants on the same product — can use different modes.
  • DATABASE — each tenant gets a dedicated database. Maximum isolation, higher cost.
  • SCHEMA — each tenant gets a dedicated schema inside a shared database. Efficient density, lower cost.

DATABASE vs. SCHEMA

DimensionDATABASESCHEMA
Physical isolationComplete — separate database per tenant.Logical — separate schema inside a shared database.
Blast radiusConfined to a single tenant’s database.Wider — a database-level incident can affect every tenant on that instance.
Selective restoreRestore one tenant independently, including point-in-time recovery.Harder — restores operate on the shared database; per-tenant restore requires extracting a single schema.
CostHigher — infrastructure scales per tenant.Lower — tenants share a database instance.
Performance isolationStrong — tenants do not contend within the same database.Weaker — tenants share instance resources and can contend.
Best forLarge, regulated, high-volume, or noisy-neighbor-sensitive tenants.Many smaller tenants where density and cost efficiency matter.

Blast radius

Blast radius is the scope of tenants affected when something goes wrong — a failed migration, a corrupt index, a runaway query, or a restore. In DATABASE mode the blast radius is a single tenant, because each tenant is physically separate. In SCHEMA mode the blast radius is wider, because tenants share a database instance and therefore share its failure and maintenance surface. Minimizing blast radius is the main reason regulated or high-value tenants are placed in DATABASE mode.

Other datastores

The DATABASE vs. SCHEMA distinction above applies to PostgreSQL. Other datastores enforce tenant isolation differently:
  • MongoDB uses a separate database per tenant (one database per tenantId). This applies in both DATABASE and SCHEMA modes — MongoDB does not use schemas, so the isolation unit is always a dedicated database named after the tenantId.
  • RabbitMQ uses a separate virtual host (vhost) per tenant. The vhost is provisioned automatically during the tenant onboarding flow and is named after the tenantId. Credentials are scoped to the vhost, so a misconfigured consumer cannot reach another tenant’s queues.
Selective restore: per-tenant restore is supported for PostgreSQL and MongoDB — both are tenant-scoped. RabbitMQ state is ephemeral by nature, so “restore” means reprovisioning the vhost and re-delivering any unacked messages from persistent storage where applicable.

Migrating from SCHEMA to DATABASE

A tenant can be promoted from SCHEMA to DATABASE mode as it grows, without re-issuing tokens or changing the tenant’s identity — isolation is a property of the service, not the tenant.
1

Provision a dedicated database

The platform provisions a new isolated database for the tenant and runs migrations, as described in automatic provisioning.
2

Migrate the tenant's data

The tenant’s data is moved from its shared-database schema into the new dedicated database.
3

Repoint the service

The tenant’s service registration is updated to the DATABASE-mode configuration. The tenantId claim is unchanged, so integrations keep working without modification.
Starting in SCHEMA mode and promoting individual tenants to DATABASE mode keeps early costs low while reserving dedicated databases for the tenants that need them. See Use cases for worked examples.

What this means for you


If you are a SaaS customer

Nothing changes in how you use the API. Authenticate, get your token, and make requests. The platform handles isolation transparently. You don’t need to manage tenant identifiers or worry about data leaking between customers.

If you are a BYOC operator running multi-tenant

You configure which tenants exist and how their databases are provisioned. Your clients authenticate through Access Manager and receive scoped tokens. The platform routes each request to the correct tenant database automatically.

If you are running single-tenant (BYOC or local development)

Multi-tenancy is disabled by default. Your existing setup continues to work without changes. No JWT tenant claim is required, and authentication can be optional depending on your configuration.

Configuration (BYOC operators)


Multi-tenancy is disabled by default in every product. To enable it, set MULTI_TENANT_ENABLED=true in the environment of each product you want to run multi-tenant (Midaz, Tracer, Reporter). Once enabled, the product requires authentication on every request and a reachable multi-tenancy service endpoint.

Core settings

These variables apply to every multi-tenant-capable product (Midaz Ledger, Midaz CRM, Tracer, Reporter):
VariableDescriptionDefault
MULTI_TENANT_ENABLEDEnable multi-tenant mode. When false, the platform runs in single-tenant mode.false
MULTI_TENANT_URLURL of the multi-tenancy service endpoint. Required when multi-tenant is enabled.
MULTI_TENANT_SERVICE_API_KEYAPI key for authenticating with the multi-tenancy service. Required when multi-tenant is enabled.
MULTI_TENANT_CONNECTIONS_CHECK_INTERVAL_SECHow often (seconds) the platform revalidates tenant configurations from the service.
MULTI_TENANT_CACHE_TTL_SECHow long (seconds) tenant configuration is cached locally before re-fetching. Set to 0 to disable caching.120

Circuit breaker

Protects against multi-tenancy service outages by failing fast when the service is unavailable:
VariableDescriptionDefault
MULTI_TENANT_CIRCUIT_BREAKER_THRESHOLDConsecutive failures before the circuit opens.5
MULTI_TENANT_CIRCUIT_BREAKER_TIMEOUT_SECHow long (seconds) the circuit stays open before retrying.30

Redis cache

Multi-tenant mode uses Redis to cache tenant configurations across instances:
VariableDescriptionDefault
MULTI_TENANT_REDIS_HOSTRedis server hostname.
MULTI_TENANT_REDIS_PORTRedis server port.6379
MULTI_TENANT_REDIS_PASSWORDRedis authentication password.
MULTI_TENANT_REDIS_TLSEnable TLS for the Redis connection.false

CRM-specific settings

These variables are only available in the CRM component and control connection pool behavior for multi-tenant database connections:
VariableDescriptionDefault
MULTI_TENANT_TIMEOUTHTTP client timeout (seconds) for requests to the multi-tenancy service.30
MULTI_TENANT_MAX_TENANT_POOLSMaximum number of concurrent database connection pools (one per active tenant).100
MULTI_TENANT_IDLE_TIMEOUT_SECHow long (seconds) before an idle tenant connection pool is evicted.300
For most deployments, the defaults work well. Tune CACHE_TTL_SEC and CONNECTIONS_CHECK_INTERVAL_SEC based on how frequently you add or modify tenants — lower values mean faster propagation of tenant changes, higher values reduce load on the multi-tenancy service.
MULTI_TENANT_ENABLED=true requires PLUGIN_AUTH_ENABLED=true. Authentication must be active for tenant isolation to work — the platform resolves tenants from the JWT claim.

Automatic provisioning

How a tenant’s databases, broker, and credentials are provisioned.

Use cases

When to choose DATABASE vs. SCHEMA isolation, with a migration path.

Deployment models

Understand the differences between SaaS, BYOC Single-Tenant, and BYOC Multi-Tenant.

Security

Learn about tenant isolation guarantees and the shared responsibility model.

Access Manager

Understand how authentication and JWT-based tenant resolution work.

Organizations

Learn how organizations are structured within a tenant.