Skip to content

@noctcore/eslint-plugin-prisma

Prisma tenancy, data integrity and transaction guardrails around a tenant-scoping client extension.

Multi-tenant Prisma code fails quietly: a query through the unscoped client with no tenant filter, a tenant id taken from the request body, two writes that should be atomic and are not, an audit log written inside a transaction that rolls it back with the work, a soft-deleted row that comes back in a list.

It will yell at you about which client you query through and what your where contains. The six preset rules hold with no project knowledge. Four more need your model registry (tenantModels, softDeleteModels, restrictions) and are deliberately left out of the preset, because a rule that reports nothing would read as coverage you do not have. mutation-entry-must-reach-audit needs type information and follows calls across files. It is a bad fit if you are not multi-tenant, or if tenancy lives in Postgres row-level security rather than a Prisma client extension; most of these rules assume the extension pattern.

Install
npm install --save-dev @noctcore/eslint-plugin-prisma @typescript-eslint/parser
# or: bun add -D / pnpm add -D @noctcore/eslint-plugin-prisma @typescript-eslint/parser
eslint.config.js
// eslint.config.js
import tsParser from '@typescript-eslint/parser';
import prisma from '@noctcore/eslint-plugin-prisma';
export default [
{
...prisma.configs.recommended,
files: ['**/*.{ts,tsx}'],
languageOptions: { parser: tsParser },
},
];
// Rules outside the preset are enabled one by one, e.g.
// { rules: { 'noctcore-prisma/mutation-entry-must-reach-audit': 'error' } }

The recommended preset enables 7 of 12 rules.

Each rule links to its page, with the options it takes and Incorrect and Correct examples. A good first read is no-unscoped-prisma-outside-allowlist.

RuleWhat it reportsPresetFixTypes
mutation-entry-must-reach-auditRequire a mutation entry point whose type-resolved call graph reaches a Prisma write to also reach an audit write. Reports only when the whole graph was read.not listedrequired
no-audit-write-in-transactionDisallow an audit-log write inside a $transaction callback, where it rolls back with the business work. It does not check that mutations are audited at all.error
no-cross-tenant-id-in-whereDisallow a Prisma query or write whose tenant id in where or data is read from client input. Without row-level security, a client-supplied tenant id is a cross-tenant access (IDOR).error
no-raw-sql-outside-allowlistDisallow raw Prisma SQL ($queryRaw, $executeRaw, $queryRawTyped, *Unsafe) that can touch a table outside an allowlist. A raw query has no model, so a tenant-scope extension passes it through unscoped.error
no-request-body-in-writeDisallow a Prisma write whose data (or where) is the raw request body. Passing client input straight through lets a caller set any column (mass assignment) or widen the filter.error
no-unscoped-prisma-outside-allowlistDisallow the unscoped Prisma client and tenant-scope escape-hatch functions outside an allowlist of seeds, migrations, isolation tests, and designated system files.error
prisma-tx-uses-tx-not-clientInside a $transaction(async (tx) => ...) callback, writes must go through the tx parameter, not the outer client, so they participate in the transaction and roll back together.error
prisma-write-in-transactionDisallow two or more Prisma writes in a single function/method body that are not wrapped in a $transaction. A partial failure between writes leaves half-written state.error
restrict-model-writesRestrict Prisma writes to configured models (or to configured columns of them) to the files that own those writes, including nested relation writes. It fences who writes; it does not validate which values or state transitions are legal.not listed
soft-deletable-tables-require-deleted-atRequire a filtered read or bulk write on a soft-deletable Prisma model to exclude soft-deleted rows in its where. Soft delete is convention only, with no Prisma extension injecting the filter, so a query that omits it reads and mutates deleted rows.not listed
tenant-scoped-tables-require-whereRequire every tenant field in the where of a read or bulk write on a tenant-scoped model through the unscoped client, and a scope column in the where of any query on a hand-scoped model.not listed
tenant-write-must-carry-tenant-idRequire every tenant field in the data of a create on a tenant-scoped Prisma model through the unscoped client, which does not inject the tenant scope.not listed

Preset: severity in configs.recommended; off means the preset registers the rule switched off, not listed means it leaves the rule out; both are opt-in, so you turn the rule on yourself. Fix: whether the rule ships an autofix or an editor suggestion. Types: whether the rule needs a type-checked program (parserOptions.projectService).