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 logsmodel?: {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 logsmodel?: {$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 modelsxprisma.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 modelconst ctx = Prisma.getExtensionContext(this)// `ctx.name` returns the name of the current modelconsole.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 onInput
.Exact
makes sure that a generic typeInput
strictly complies with the type that you specify inShape
. It narrowsInput
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 withArgs
. As withArgs
,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,},})}