Shared Prisma Client extensions
You can share your Prisma Client extensions with other users, either as packages or as modules, and import extensions that other users create into your project.
If you would like to build a shareable extension, we also recommend using the prisma-client-extension-starter
template.
Install a shared, packaged extension
In your project, you can install any Prisma Client extension that another user has published to npm
. To do so, run the following command:
npm install prisma-extension-<package-name>
For example, if the package name for an available extension is prisma-extension-find-or-create
, you could install it as follows:
npm install prisma-extension-find-or-create
To import the find-or-create
extension from the example above, and wrap your client instance with it, you could use the following code. This example assumes that the extension name is findOrCreate
.
import findOrCreate from 'prisma-extension-find-or-create'
const prisma = new PrismaClient().$extends(findOrCreate)
const user = await prisma.user.findOrCreate()
When you call a method in an extension, use the constant name from your $extends
statement, not prisma
. In the above example,xprisma.user.findOrCreate
works, but prisma.user.findOrCreate
does not, because the original prisma
is not modified.
Create a shareable extension
When you want to create extensions other users can use, and that are not tailored just for your schema, Prisma ORM provides utilities to allow you to create shareable extensions.
To create a shareable extension:
- Define the extension as a module using
Prisma.defineExtension
- Use one of the methods that begin with the
$all
prefix such as$allModels
or$allOperations
Define an extension
Use the Prisma.defineExtension
method to make your extension shareable. You can use it to package the extension to either separate your extensions into a separate file or share it with other users as an npm package.
The benefit of Prisma.defineExtension
is that it provides strict type checks and auto completion for authors of extension in development and users of shared extensions.
Use a generic method
Extensions that contain methods under $allModels
apply to every model instead of a specific one. Similarly, methods under $allOperations
apply to a client instance as a whole and not to a named component, e.g. result
or query
.
You do not need to use the $all
prefix with the client
component, because the client
component always applies to the client instance.
For example, a generic extension might take the following form:
export default Prisma.defineExtension({
name: 'prisma-extension-find-or-create', //Extension name
model: {
$allModels: {
// new method
findOrCreate(/* args */) {
/* code for the new method */
return query(args)
},
},
},
})
Refer to the following pages to learn the different ways you can modify Prisma Client operations:
- Modify all Prisma Client operations
- Modify a specific operation in all models of your schema
- Modify all operations in all models of your schema
For versions earlier than 4.16.0
The Prisma
import is available from a different path shown in the snippet below:
import { Prisma } from '@prisma/client/scripts/default-index'
export default Prisma.defineExtension({
name: 'prisma-extension-<extension-name>',
})
Publishing the shareable extension to npm
You can then share the extension on npm
. When you choose a package name, we recommend that you use the prisma-extension-<package-name>
convention, to make it easier to find and install.
Call a client-level method from your packaged extension
There's currently a limitation for extensions that reference a PrismaClient
and call a client-level method, like the example below.
If you trigger the extension from inside a transaction (interactive or batched), the extension code will issue the queries in a new connection and ignore the current transaction context.
Learn more in this issue on GitHub: Client extensions that require use of a client-level method silently ignore transactions.
In the following situations, you need to refer to a Prisma Client instance that your extension wraps:
- When you want to use a client-level method, such as
$queryRaw
, in your packaged extension. - When you want to chain multiple
$extends
calls in your packaged extension.
However, when someone includes your packaged extension in their project, your code cannot know the details of the Prisma Client instance.
You can refer to this client instance as follows:
Prisma.defineExtension((client) => {
// The Prisma Client instance that the extension user applies the extension to
return client.$extends({
name: 'prisma-extension-<extension-name>',
})
})
For example:
export default Prisma.defineExtension((client) => {
return client.$extends({
name: 'prisma-extension-find-or-create',
query: {
$allModels: {
async findOrCreate({ args, query, operation }) {
return (await client.$transaction([query(args)]))[0]
},
},
},
})
})