Prisma Nested Middleware
Prisma Nested Middleware is a utility library designed to extend Prisma's native middleware capabilities, specifically for handling nested write operations and relations within queries. While standard Prisma middleware (version 4.0.0 is the latest as of January 2024, with a consistent release cadence) is effective for top-level queries, it lacks the ability to intercept and modify operations on nested relations. This library addresses that limitation by providing a `createNestedMiddleware` function that wraps your middleware, allowing it to be called for every nested relation in a Prisma query. It exposes an enhanced `NestedParams` object, which includes critical context like `scope`, `modifier`, `logicalOperators`, and `relations` that are unavailable in standard Prisma middleware, enabling fine-grained control over complex data manipulations.
Common errors
-
Prisma middleware not being called for nested writes
cause Prisma's native middleware (`prisma.$use`) is designed for top-level queries only and does not inherently intercept operations within nested `create`, `update`, or `connect` clauses.fixWrap your middleware function with `createNestedMiddleware` from this library and apply it to your `PrismaClient` using `$use`. This library specifically enables middleware execution for nested operations. -
Error parsing invalid logical where arrays
cause Older versions of `prisma-nested-middleware` had a bug in parsing malformed logical `where` conditions (e.g., `AND`, `OR`, `NOT`).fixUpgrade `prisma-nested-middleware` to version `3.0.2` or higher, which includes a fix for this issue. Additionally, ensure your `where` arrays adhere to Prisma's expected structure for logical operators. -
Queries that use Json NullTypes are not working correctly
cause A bug in older versions of `prisma-nested-middleware` affected queries involving Prisma's JSON `NullTypes`.fixUpgrade `prisma-nested-middleware` to version `3.0.1` or higher. This version contains a fix for handling JSON `NullTypes` correctly.
Warnings
- breaking Version 4.0.0 removed the ability for middleware to be called with the 'select' action for 'select' objects found within an 'include' statement. Middleware that relied on this specific call pattern will no longer function as expected for such scenarios.
- breaking In version 3.0.0, the structure for nested 'create' actions was reverted: `params.args` no longer moves its content into a `data` field. This directly reverses the breaking change introduced in v2.0.0. If you upgraded from v2.x, your middleware might be broken.
- breaking Version 2.0.0 introduced a breaking change where for nested 'create' actions, `params.args` would contain its content within a `data` field (e.g., `params.args.data`). Middleware written for prior versions would break, as they would expect `params.args` to directly hold the data.
- gotcha The `NestedParams` object provided by this library extends `Prisma.MiddlewareParams` with additional fields like `scope`, `modifier`, `logicalOperators`, and `relations`. Not accounting for these enriched fields can lead to incomplete middleware logic or runtime errors when attempting to access them.
- gotcha Prisma's built-in `$use` middleware is deprecated in Prisma ORM v4.16.0 and removed in v6.14.0. Users of `prisma-nested-middleware` should be aware that the underlying mechanism it leverages is being phased out by Prisma.
Install
-
npm install prisma-nested-middleware -
yarn add prisma-nested-middleware -
pnpm add prisma-nested-middleware
Imports
- createNestedMiddleware
const createNestedMiddleware = require('prisma-nested-middleware')import { createNestedMiddleware } from 'prisma-nested-middleware' - NestedParams
import type { NestedParams } from 'prisma-nested-middleware' - PrismaClient
import { PrismaClient } from '@prisma/client'
Quickstart
import { PrismaClient } from '@prisma/client';
import { createNestedMiddleware, NestedParams } from 'prisma-nested-middleware';
const prisma = new PrismaClient();
prisma.$use(createNestedMiddleware(async (params: NestedParams, next) => {
console.log(`[${params.model}] Action: ${params.action}`);
if (params.scope) {
console.log(' Scope:', params.scope.parentParams?.model, '->', params.scope.relation?.to);
}
// Example: Modify 'create' args for a nested operation
if (params.action === 'create' && params.model === 'Post' && params.scope) {
console.log(' Intercepted nested Post create:', params.args);
// Ensure params.args structure for nested creates, which can vary by version
if ('data' in params.args && typeof params.args.data === 'object') {
// For v2.x to <v3.0.0, data was inside params.args.data
params.args.data.title = `[Nested] ${params.args.data.title}`;
} else if (typeof params.args === 'object') {
// For v3.x onwards, data is directly in params.args
params.args.title = `[Nested] ${params.args.title}`;
}
}
const result = await next(params);
if (result) {
console.log(`[${params.model}] Result for ${params.action}:`, result);
}
return result;
}));
async function main() {
await prisma.user.deleteMany({});
await prisma.post.deleteMany({});
const user = await prisma.user.create({
data: {
email: 'test@example.com',
name: 'Test User',
posts: {
create: [
{ title: 'First Post', content: 'Content 1' },
{ title: 'Second Post', content: 'Content 2' }
],
},
},
include: { posts: true },
});
console.log('\nCreated user with nested posts:', JSON.stringify(user, null, 2));
}
main().catch(console.error).finally(() => prisma.$disconnect());