Multitenant

Next.js

`@multitenant/next`, `next-app`, `next-pages` — meta package, App Router, Pages Router.

Next.js — Meta package

Meta-package for App Router apps: re-exports @multitenant/core, @multitenant/config, @multitenant/react, and @multitenant/next-app so you can depend on one scope for typical Next.js setups.

Install

npm install @multitenant/next next react react-dom

When to use

  • Prefer @multitenant/next when you want one install line and tree-shaking still keeps bundles reasonable.
  • Use @multitenant/next-app alone if you only need the middleware/server surface and already depend on core separately.

Next.js — App Router

Next.js App Router integration: middleware for Edge-safe tenant resolution (headers), plus server helpers to read x-tenant-key, x-market-key, and related headers. Subpaths /auto and /auto-node re-export config-aware shortcuts.

Use @multitenant/next-app (or @multitenant/next). Keep middleware Edge-safe (static JSON / small bundle); put DB in Route Handlers, Server Actions, or RSC with runtime = 'nodejs' when needed.

Install

npm install @multitenant/next-app next react react-dom

Peers: next, and typically @multitenant/core for createTenantRegistry.

Main APIs

  • createTenantMiddleware(registry, options?) — sets resolution headers; onMissingTenant: 'passthrough' | 'warn' | 'throw'
  • getTenantFromHeaders, requireTenant — in Server Components / Route Handlers / nodejs runtime

Resolution vs data access

RuntimeTenant resolutionDatabase / heavy Node
Edge middlewarecreateTenantMiddleware + static configNo
Node servergetTenantFromHeaders / requireTenantYes — e.g. runWithTenantScope

Middleware defaults

  • onMissingTenant: 'passthrough' — avoids throwing on raw localhost during next dev; use multitenant dev + domains.local hosts, or 'throw' when every request must resolve.
  • Prefer x-forwarded-host behind a reverse proxy (middleware normalizes the left-most host).
  • Headers forwarded to the app: x-tenant-key, x-market-key, x-tenant-env, optional x-tenant-flags (JSON).

Shared registry module

lib/tenant-registry.ts

import type { TenantsConfig } from '@multitenant/core';
import { createTenantRegistry } from '@multitenant/core';
import tenantsConfig from '../tenants.config.json';

export const tenantRegistry = createTenantRegistry(tenantsConfig as TenantsConfig);

export function multitenantEnv() {
  return (process.env.MULTITENANT_ENV ?? process.env.TENANTIFY_ENV ?? 'local') as import('@multitenant/core').EnvironmentName;
}

middleware.ts

import { createTenantMiddleware } from '@multitenant/next-app';
import { multitenantEnv, tenantRegistry } from '@/lib/tenant-registry';

export const middleware = createTenantMiddleware(tenantRegistry, {
  environment: multitenantEnv(),
});

export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)'],
};

Route Handler

import { headers } from 'next/headers';
import { NextResponse } from 'next/server';
import { getTenantFromHeaders } from '@multitenant/next-app';
import { multitenantEnv, tenantRegistry } from '@/lib/tenant-registry';

export async function GET() {
  const h = await headers();
  const resolved = getTenantFromHeaders(h, tenantRegistry, { environment: multitenantEnv() });
  return NextResponse.json({
    tenantKey: resolved?.tenantKey ?? null,
    marketKey: resolved?.marketKey ?? null,
  });
}

Server Action

'use server';

import { headers } from 'next/headers';
import { getTenantFromHeaders } from '@multitenant/next-app';
import { multitenantEnv, tenantRegistry } from '@/lib/tenant-registry';

export async function currentTenantKey(): Promise<string | null> {
  const h = await headers();
  const resolved = getTenantFromHeaders(h, tenantRegistry, { environment: multitenantEnv() });
  return resolved?.tenantKey ?? null;
}

Use requireTenant when a missing tenant must hard-fail — it throws TenantNotFoundError.

Server Actions & Node-only code

Set export const runtime = 'nodejs' on routes/layouts that use fs, native drivers, or @multitenant/database.

Zero-config shortcut

@multitenant/next-app/autocreateTenantMiddlewareFromConfig(json, { environment }) for a single-file middleware (see Examples — Next.js (App Router)).


Next.js — Pages Router

Next.js Pages Router helpers: getServerSideProps and API route wrappers that attach ResolvedTenant (and market) to the request context.

You typically createTenantRegistry once (e.g. lib/tenant-registry.ts) and pass registry + environment into helpers.

Install

npm install @multitenant/next-pages next react react-dom

Package name on npm is next-pages (monorepo folder next-paages).

Main APIs

ExportRole
withTenantGSSPWrap getServerSideProps — receives context with resolvedTenant (or triggers notFound)
withTenantApiWrap NextApiHandlerreq.tenant pattern or JSON errors

Behaviour when host does not resolve

APIResult
withTenantApi404 response { error, code: 'MULTITENANT_TENANT_NOT_FOUND' }
withTenantGSSP{ notFound: true } — Next notFound(); no TenantNotFoundError thrown inside GSSP

See Errors.

Scaffold

npx @multitenant/cli init --framework next-pages

Install @multitenant/next-pages, next, react, @multitenant/core.

For the App Router, see Next.js — App Router above.

See also

On this page