Resolution chain
Resolution chain
The tenant.global middleware (installed by the layer, on unless xTenancy.enabled: false) resolves the active tenant according to xTenancy.strategy. It runs after auth-better's auth.global/organization.global (alphabetical order), so when xAuth.organization.enabled is on, auth-better's org routes already activate the org — the tenancy middleware short-circuits on tenant.slug === slug.
Strategies
path (default)
Reads the slug from ${pathPrefix}/:slug — default /org/:slug, matching auth-better's org routes — and activates it via resolveBySlug(). Unresolvable slugs redirect to xTenancy.fallbackRoute when set.
export default defineAppConfig({
xTenancy: {
strategy: 'path',
pathPrefix: '/org',
fallbackRoute: '/org', // redirect target for unknown slugs
},
})
subdomain
Maps the request host against xTenancy.rootDomain: the left-most host label is the organization slug (acme.app.example.com → acme), activated via the standard set-active endpoint. Requires wildcard DNS / vhost for *.{rootDomain} routing to the Nuxt app.
export default defineAppConfig({
xTenancy: {
strategy: 'subdomain',
rootDomain: 'app.example.com', // required for this strategy
},
})
header
No routing at all — the middleware no-ops. The tenant follows the session's active organization, and only the X-Tenant-ID request header carries it to APIs. Use this for API-only tenant scoping or when tenancy is orthogonal to the URL space.
Slug resolution caveat (upstream better-auth bug)
resolveBySlug() resolves slugs against the organization/list response, not get-full-organization?organizationSlug=. Verified against better-auth 1.6.5: the client's organization.getFullOrganization({ organizationId, organizationSlug }) silently drops those GET params, so slug lookup via that endpoint always returns the active org. The list is the reliable client-side slug → id source.
This upstream bug also affects auth-better's own organization.global slug sync and direct SSR hits of /org/:slug (the better-auth atoms resolve client-side only, so a direct server-rendered /org/:slug bounces to /org). Navigate org routes client-side until the upstream fix lands.
AI Context
guide: resolution-chain
package: "@xenterprises/nuxt-x-tenancy"
use-when: >
Choosing or debugging the tenant resolution strategy. path (default,
/org/:slug), subdomain (host label vs rootDomain), header (no routing,
X-Tenant-ID only). Middleware runs after auth-better's globals.
resolveBySlug uses organization/list because better-auth's
getFullOrganization drops slug GET params (≤1.6.5).
