Prisma Next is in early access.Read the docs

Built-in: lints

The lints middleware inspects each query's structure before it runs and blocks or warns on risky shapes.

The lints middleware inspects the structure of every query before it executes and blocks or warns on shapes that are usually mistakes, like a DELETE with no WHERE clause.

Register it on the runtime; the defaults are useful without configuration:

src/prisma/db.ts
import postgres from '@prisma-next/postgres/runtime';
import { lints } from '@prisma-next/sql-runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
  middleware: [lints()],
});

lints is SQL-family middleware (it declares familyId: 'sql'), so it registers on PostgreSQL runtimes. It ships with @prisma-next/sql-runtime, which comes in through @prisma-next/postgres.

The rules

Lints run in beforeExecute, against the query plan's AST. Each rule has a severity: error throws and blocks the query before it reaches the database, warn logs through the runtime log and lets the query run.

RuleCodeDefault severityFires when
DELETE without WHERELINT.DELETE_WITHOUT_WHEREerrorA DELETE has no WHERE clause
UPDATE without WHERELINT.UPDATE_WITHOUT_WHEREerrorAn UPDATE has no WHERE clause
No LIMITLINT.NO_LIMITwarnA SELECT has no LIMIT clause
SELECT starLINT.SELECT_STARwarnA query selects all columns instead of naming them

A warning is emitted as a structured event on the runtime's log:

Lint warning
warn {
  code: 'LINT.NO_LIMIT',
  message: 'Unbounded SELECT may return large result sets',
  details: { table: 'user' }
}

Configure severities

Raise or lower any rule per project through severities. For example, treat unbounded selects as hard failures in a service where every list endpoint must paginate:

src/prisma/db.ts
lints({
  severities: {
    noLimit: 'error',
    selectStar: 'warn',
  },
});

The severity keys are deleteWithoutWhere, updateWithoutWhere, noLimit, and selectStar, plus readOnlyMutation for the raw-SQL guardrail described below. The options type also accepts unindexedPredicate, but no rule emits that finding in v0.14.

Raw SQL

Queries built with the ORM client or the SQL query builder carry a typed AST, and the rules above inspect it structurally. Raw SQL does not have that structure, so lints falls back to text heuristics for raw plans: it flags select *, a missing LIMIT, and a mutation smuggled through a raw query marked read-only (LINT.READ_ONLY_MUTATION). The raw heuristics carry their own defaults: select * escalates to error for raw plans (stricter than the AST rule's warn), a missing LIMIT stays a warning, and a read-only-intent mutation is an error. The severities keys above override raw findings too. Control the fallback with fallbackWhenAstMissing:

src/prisma/db.ts
lints({ fallbackWhenAstMissing: 'raw' }); // default: heuristic checks on the SQL text
lints({ fallbackWhenAstMissing: 'skip' }); // skip linting for plans without an AST

Heuristics can misread SQL that a structural check would classify correctly, so treat raw-SQL lint findings as a prompt to look at the query rather than a verdict.

Common gotchas

See also

On this page