NestJS
Scope every NestJS request with a module and interceptor - Express or Fastify, any ORM.
tenancyjs-integration-nest brings tenant scoping to NestJS 11. Register the tenancy module and an
interceptor opens a tenant scope for the lifetime of each request; your controllers and providers run
inside it. It works on both the Express and Fastify platforms.
Works with any ORM. Prisma · Knex · TypeORM · Sequelize · Drizzle · Mongoose.
NestJS is fully supported, but tenancy init doesn't scaffold it yet - this is the manual setup (a
few lines). See Installation.
Install
npm install tenancyjs-core tenancyjs-integration-nest tenancyjs-adapter-prisma @prisma/clientWire it up
Provide your application-owned manager and resolution service. TenancyModule registers its global
guard and interceptor; do not register a second copy.
import { Module } from "@nestjs/common";
import { TenantResolutionChain, HeaderTenantResolver } from "tenancyjs-identifiers";
import { TenancyModule } from "tenancyjs-integration-nest";
import { manager, tenantStore } from "./tenancy";
const resolver = new TenantResolutionChain({
resolvers: [new HeaderTenantResolver()],
store: tenantStore,
});
@Module({
imports: [TenancyModule.forRoot({ manager, resolver })],
})
export class AppModule {}Mark tenant routes explicitly and use your adapter's protected API inside the handler:
import { Controller, Get } from "@nestjs/common";
import { TenantRoute } from "tenancyjs-integration-nest";
import { typeormTenancy } from "./tenancy";
import { Post } from "./entities/post";
@Controller("posts")
export class PostsController {
@Get()
@TenantRoute()
list() {
return typeormTenancy.run((client) =>
client.repository(Post).findBy({ status: "open" }),
);
}
}How it behaves
- Each request resolves its tenant and runs inside the scope; ORM queries through the adapter are scoped.
- A resolution failure fails closed with the correct HTTP status before your controller runs.
- Authorization guards may inject
NestTenantResolutionStoreto read the resolved tenant. The canonicalTenancyManagercontext begins later in the interceptor and covers the handler Observable. - Unmarked routes are neither tenant nor central routes.
The optional executor setting is for transaction executors whose scoped resource is already available
to application operations (for example an ALS-backed integration). Callback-only facades such as
TypeORM and Sequelize should normally be called directly in the handler as shown above; passing them as
an executor does not inject their callback client into Nest providers.
Use a different ORM
For the exact lifecycle and security boundary, see the package README.