Add custom methods to your models

You can use the model Prisma Client extensions component type to add custom methods to your models. We introduced this feature in version 4.7.0.

Possible uses for the model component include the following:

  • New operations to operate alongside existing Prisma Client operations, such as findMany
  • Encapsulated business logic
  • Repetitive operations
  • Model-specific utilities

Enable the preview feature

Before you create Prisma Client extensions, you must enable the clientExtensions feature flag in the generator block of your schema.prisma file, as follows:

generator client {
provider = "prisma-client-js"
previewFeatures = ["clientExtensions"]
}

Add a custom method

Use the $extends client-level method to create an extended client. An extended client is a variant of the standard Prisma Client that is wrapped by one or more extensions. Use the model extension component to add methods to models in your schema.

Add a custom method to a specific model

To extend a specific model in your schema, use the following structure. This example adds a method to the user model.

const xprisma = prisma.$extends({
name?: '<name>', // (optional) names the extension for error logs
model?: {
user: { ... } // in this case, we extend the `user` model
},
});

Example

The following example adds a method called signUp to the user model. This method creates a new user with the specified email address.

const xprisma = prisma.$extends({
model: {
user: {
async signUp(email: string) {
await prisma.user.create({ data: { email } })
},
},
},
})

You would call signUp in your application as follows:

const user = await xprisma.user.signUp('john@prisma.io')

When you call a method in an extension, use the constant name from your $extends statement, not prisma. In the above example, xprisma.user.signUp works, but prisma.user.signUp does not, because the original prisma is not modified.

Add a custom method to all models in your schema

To extend all models in your schema, use the following structure:

const xprisma = prisma.$extends({
name?: '<name>', // `name` is an optional field that you can use to name the extension for error logs
model?: {
$allModels: { ... }
},
})

Example

The following example adds a validate method to all models.

const xprisma = new prisma.$extends({
model: {
$allModels: {
validate(data: unknown) {
/* Generic validation logic */
},
},
},
})

You would call validate in your application as follows:

// `validate` method available on all models
xprisma.user.validate(someData)
xprisma.post.validate(someData)

Call a custom method from another custom method

You can call a custom method from another custom method, if the two methods are declared on the same model. For example, you can call a custom method on the user model from another custom method on the user model. It does not matter if the two methods are declared in the same extension or in different extensions.

To do so, use Prisma.getExtensionContext(this).methodName. Note that you cannot use prisma.user.methodName. This is because prisma is not extended yet, and therefore does not contain the new method.

For example:

prisma.$extends({
model: {
user: {
firstMethod() {
...
}
secondMethod() {
Prisma.getExtensionContext(this).firstMethod()
}
}
}
})

Get the current model name at runtime

This feature is available from version 4.9.0.

You can get the name of the current model at runtime with Prisma.getExtensionContext(this).name. You might use this to write out the model name to a log, to send the name to another service, or to branch your code based on the model.

For example:

// `ctx` refers to the current model
const ctx = Prisma.getExtensionContext(this)
// `ctx.name` returns the name of the current model
console.log(ctx.name)

Advanced type safety: improve the type safety and developer experience of your custom model methods

This feature is available from version 4.9.0.

To help you create highly type-safe extensions, Prisma Client provides a set of type utilities that tap into input and output types. They are fully dynamic, which means that they adapt to any given model and schema. You can use them to improve the auto-completion and developer experience of your custom model methods. This is especially useful in shared extensions.

The following type utilities are available in Prisma Client:

  • Exact<Input, Shape>: Enforces strict type safety on Input. Exact makes sure that a generic type Input strictly complies with the type that you specify in Shape. It narrows Input down to the most precise types.
  • Args<Type, Operation>: Retrieves the input arguments for any given model and operation. This is particularly useful for extension authors who want to do the following:
    • Re-use existing types to extend or modify them.
    • Benefit from the same auto-completion experience as on existing operations.
  • Result<Type, Arguments, Operation>: Takes the input arguments and provides the result for a given model and operation. You would usually use this in conjunction with Args. As with Args, Result helps you to re-use existing types to extend or modify them.
  • Payload<Type, Operation>: Retrieves the entire structure of the result, as scalars and relations objects for a given model and operation. For example, you can use this to determine which keys are scalars or objects at a type level.

The following example creates a new operation, customCall, based on findFirst. It has all of the arguments that findFirst has, with an additional property, customProperty.

const prisma = new PrismaClient()
const xprisma = prisma.$extends({
model: {
$allModels: {
// Define a new operation `customCall`.
// T corresponds to the current model,
// A corresponds to the arguments for the operation.
customCall<T, A>(
// `this` is the current type (for example
// it might be `prisma.user` at runtime).
this: T,
x: Prisma.Exact<
A,
// For `customCall`, use the arguments from model `T` and the
// operation `findFirst`. Add `customProperty` to the operation.
Prisma.Args<T, 'findFirst'> & { customProperty: boolean }
>
// Get the correct result types for the model of type `T`,
// and the arguments of type `A` for `findFirst`.
// `Prisma.Result` computes the result for a given operation
// such as `select {id: true}` in function `main` below.
//
): Prisma.Result<T, A, 'findFirst'> {
// Override type safety here, because we cannot
// predict the result types in advance.
return {} as any
},
},
},
})
async function main() {
const test0 = xprisma.link.customCall({
customProperty: true,
select: {
id: true,
},
})
}
Edit this page on GitHub