Middleware
Note: Middleware is a stable feature as of version 2.5.0.
Middleware allows you to perform an action before or after each query runs. Use the prisma.$use
method to add middleware:
script.ts
1const prisma = new PrismaClient()23// Middleware 14prisma.$use(async (params, next) => {5 // Manipulate params here6 const result = next(params);7 // See results here8 return result;9})1011// Middleware 212prisma.$use(async (params, next) => {13 // Manipulate params here14 const result = next(params);15 // See results here16 return result;17})1819// Queries here
Use cases for middleware include:
- Setting or overwriting a field value - for example, setting the context language of a blog post comment
- Validating input data - for example, check user input for inappropriate language via an external service
- Intercept a
delete
query and change it to anupdate
in order to perform a soft delete - Log the time taken to perform a query
Examples
Reference
params
accepts the following type:
export type MiddlewareParams = {model?: ModelNameaction: PrismaActionargs: anydataPath: string[]runInTransaction: boolean}export declare const ModelName: {User: 'User',Post: 'Post'}export declare type ModelName = (typeof ModelName)[keyof typeof ModelName]
Example:
{args: { where: { id: 15 } },dataPath: [ 'select', 'author', 'select', 'posts' ],runInTransaction: false,action: 'findMany',model: 'Post'}
Parameter descriptions:
Parameter | Description |
---|---|
action | The query type - for example, create or findMany . See CRUD reference for all available queries. |
args | Arguments that were passed into the query - for example, where , data , or orderBy . See CRUD reference for all available arguments. |
dataPath | Populated if you use the fluent API. |
model | The model type - for example, Post or User . |
runInTransaction | Returns true if the query ran in the context of a transaction. |
Tip: If you need the
model
property as a string, use:String(params.model)
Running order
If you have multiple middlewares, the running order for each separate query is:
- All logic before
await next(params)
- All logic after
await next(params)
const prisma = new PrismaClient()prisma.$use(async (params, next) => {console.log(params.args.data.title)console.log('1')const result = await next(params)console.log('4')return result})prisma.$use(async (params, next) => {console.log('2')const result = await next(params)console.log('3')return result})const create = await prisma.post.create({data: {title: 'Welcome to Prisma Day 2020',},})const create2 = await prisma.post.create({data: {title: 'How to Prisma!',},})
Output:
Welcome to Prisma Day 20201234How to Prisma!1234
Performance and appropriate use cases
Middleware executes for every query, which means that overuse has the potential to negatively impact performance. To avoid adding performance overheads:
Check the
params.model
andparams.action
properties early in your middleware to avoid running logic unnecessarily:prisma.$use(async (params, next) => {if (params.model == 'Post' && params.action == 'delete') {// Logic only runs for delete action and Post model}return next(params)})Consider whether middleware is the appropriate solution for your scenario. For example:
- If you need to populate a field, can you use the
@default
attribute? - If you need to set the value of a
DateTime
field, can you use thenow()
function or the@updatedAt
attribute? - If you need to perform more complex validation, can you use a
CHECK
constraint in the database itself?
- If you need to populate a field, can you use the