Skip to content
GitHub

Multi-Tenancy

lexigram-tenancy adds first-class multi-tenancy — identifying the current tenant, isolating its data, and propagating its context safely across async calls.


  1. Resolution — determine which tenant a request belongs to.
  2. Isolation — separate tenant data (row, schema, or database).
  3. Enforcement — bind the current context to the resolved tenant and reject requests that violate it.

Resolution runs at the edge of the request pipeline. Resolvers are tried in order; the first match wins.

ResolverSourceUse case
headerX-Tenant-ID headerAPI integrations, mobile apps
jwt_claima claim in the auth tokenOAuth2 / OIDC requests
subdomaintenant.app.comclassic SaaS
path/api/v1/{tenant}/...multi-org public portals
from lexigram import Application
from lexigram.tenancy import TenancyModule, TenancyConfig, ResolutionConfig
app = Application(name="my-saas")
app.add_module(
TenancyModule.configure(
TenancyConfig(resolution=ResolutionConfig(resolvers=["header", "jwt_claim"]))
)
)

For tests, TenancyModule.stub() provides an in-memory, header-only setup with no isolation overhead.


Once resolved, a TenantContextMiddleware stores the tenant id in a ContextVar, so it follows your code across await boundaries without being threaded through every function signature. Tenant-aware services and repositories read the current tenant from that context automatically.

See the lexigram-tenancy package docs for the exact context-accessor and tenant-scoping decorator APIs.


StrategyHowTrade-off
Row-level (shared table)every row carries a tenant_idcheapest; relies on consistent filtering
Schema (shared DB)one Postgres schema per tenantstronger isolation, moderate ops overhead
Database (separate DBs)a database per tenantstrongest isolation; highest ops cost

The isolation strategy is pluggable per tenant via the package’s strategy registry.


Mark routes as tenant-scoped so a request without a resolved, authorized tenant is rejected (401 if no tenant is present, 403 if the user doesn’t belong to it). The tenancy middleware validates the resolved tenant before the handler runs.