TenancyJS
Integrations

Next.js

Tenant context across the Edge/Node boundary in the Next.js App Router - works with any ORM.

tenancyjs-integration-next supports the Next.js App Router. Next runs middleware on the Edge and your handlers on Node, so identity has to cross that boundary. The integration handles the hand-off - your Server Components and Route Handlers see the resolved tenant.

Works with any ORM. Prisma · Knex · TypeORM · Sequelize · Drizzle · Mongoose. Prisma is the common pairing; swap the adapter for yours.

Install

npm install tenancyjs-core tenancyjs-integration-next tenancyjs-adapter-prisma @prisma/client

Set up the runtime

lib/tenancy.ts
import { createNextTenancy } from "tenancyjs-integration-next";
import { manager } from "./manager";

export const tenancy = createNextTenancy({
  manager,
  resolver: (request) => ({ id: request.headers.get("x-tenant") ?? "" }),
});

Resolve identity at the edge

Wire the edge middleware in middleware.ts so identity is resolved once, at the boundary, and carried forward:

middleware.ts
export { middleware } from "@/lib/tenancy";

export const config = {
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};

Then run scoped work inside a Route Handler or Server Component - the tenant is already in context:

app/orders/route.ts
import { tenancy } from "@/lib/tenancy";
import { db } from "@/lib/db"; // your adapter-extended client

export async function GET() {
  const orders = await tenancy.run(() => db.order.findMany());
  return Response.json(orders);
}

See ADR-0009 for how the Edge → Node identity hand-off is implemented and why it's safe.

Use a different ORM

Static routes with no tenant should not call scoped adapters - guard them, or open a central scope explicitly.

On this page