Skip to content

Database routing

What it does

TenantAdapter.modelConstructorClient() is called by Lucid every time a TenantBaseModel query starts. The adapter:

  1. Reads the active tenant via tenancy.currentId() (or HttpContext.tenant for HTTP-driven flows).
  2. Asks the active IsolationDriver for the connection name: tenant_<uuid> for schema-pg, the per-tenant database name for database-pg, the shared connection plus a tenant_id filter for rowscope-pg.
  3. Returns the connection so the query routes there.

Configuration

Configured indirectly through isolation.driver. See Data isolation.

Why it isn't a bootstrapper

Bootstrappers run on the enter / leave cycle of a tenant context. Database routing happens per query, not per context. Adapter calls are synchronous, frequent, and have to work even for code paths that never call tenancy.run() (controller calls during HTTP requests rely on HttpContext.tenant, not the bootstrapper registry).

Folding database routing into the bootstrapper registry would add overhead to every query and make the dependency direction circular, since bootstrappers depend on the adapter for their own state.

Error mode

If no driver matches the configured isolation.driver, the adapter throws on the first query with the active driver name in the message. The request fails with a 5xx. This is louder than silently falling back to a default and worth the noise.

Was this page helpful?

Released under the MIT License.