Repo of the Day
shauliz/node-express-multitenant
Published: Mar 25, 2023
Open repository ↗Multitenancy package for express based applications
Summary
node-express-multitenant is a TypeScript library that adds shared-database, shared-schema multi-tenancy to Express applications built on Prisma. It pulls a tenant identifier from each request, stores it in AsyncLocalStorage, and applies it to scoped queries through a Prisma Client Extension so developers cannot accidentally skip the tenant filter.
What it is useful for
The library fits when one Express + Prisma service serves multiple customers from a single database, separating them with a column (default account_id). It applies that filter automatically across findFirst, findFirstOrThrow, findMany, findUnique/findUniqueOrThrow, create, createMany, upsert, update, updateMany, delete, deleteMany, count, aggregate, and groupBy for any model carrying the tenant column. Models without that column are left untouched.
If a request reaches the database without a tenant ID, the library throws MissingTenantContextError and fails closed rather than returning every tenant's rows. Cross-tenant work like background jobs or admin tooling can opt out per query with the documented ignoreMultitenancy: true flag.
Documented limitations to be aware of: $queryRaw and $executeRaw are not scoped, and because Prisma rejects non-unique fields in a findUnique where clause, the library rewrites findUnique and findUniqueOrThrow to findFirst and findFirstOrThrow internally. The README also recommends compound uniques that include the tenant column to avoid upsert collisions on create when the update path is correctly suppressed.
How engineers can use it
The README documents the following setup:
- Install with
npm install node-express-multitenant. Needs Node.js>= 20, Prisma^5or^6, and Express^4or^5. - Add an
account_idcolumn to every Prisma model that should be scoped. - Mount
getMultitenancyMiddlewareafter authentication. The default readsreq.headers["account-id"], which the README flags as insecure on its own and recommends replacing with a JWT or session claim:
app.use(
getMultitenancyMiddleware((req) => req.headers["account-id"]),
);
- Wrap Prisma with the extension:
const prisma = new PrismaClient().$extends(
withMultitenancy({ tenantField: "account_id" }),
);
- Query normally.
findMany()is filtered automatically,createcalls haveaccount_idoverwritten with the request's tenant, andfindUniqueis rewritten to apply the tenant filter. The README points toexamples/express-prismafor a full wiring sketch.
Projects still on v1 must migrate: prisma.$use and addMultitenancy are removed in favor of withMultitenancy, and the -1 placeholder has been replaced by MissingTenantContextError.