Prisma Client Extensions
To use the new Prisma Client Extensions you must update to Prisma Client v4.7.0 or later and install nestjs-prisma@v0.20.0
or later.
Follow this guide or checkout the extensions example.
Prisma Extension
Create Prisma Extension
Create a file for your Prisma extension for example prisma.extension.ts
import { PrismaClient } from '@prisma/client';
export const extendedPrismaClient = new PrismaClient().$extends({
model: {
user: {
findByEmail: async (email: string) => {
return extendedPrismaClient.user.findFirstOrThrow({ where: { email } });
},
},
},
});
export type ExtendedPrismaClient = typeof extendedPrismaClient;
Export the type of your extended Prisma Client, this will be used for correct type-safety for your CustomPrismaService
.
Register Extended Prisma Client
Register your extended Prisma Client using CustomPrismaModule.forRootAsync
.
useFactory
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CustomPrismaModule } from 'nestjs-prisma';
import { extendedPrismaClient } from './prisma.extension';
@Module({
imports: [
// ✅ use `forRootAsync` when using `PrismaClient().$extends({})`
CustomPrismaModule.forRootAsync({
name: 'PrismaService',
useFactory: () => {
return extendedPrismaClient;
},
}),
// ❌ error: 'getOwnPropertyDescriptor' on proxy
// CustomPrismaModule.forRoot({
// name: 'PrismaServiceAuth',
// client: new PrismaClient().$extends({}),
// }),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
useClass
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CustomPrismaModule } from 'nestjs-prisma';
import { ExtendedPrismaConfigService } from './extended-prisma-config.service';
@Module({
imports: [
// ✅ use `forRootAsync` when using `PrismaClient().$extends({})`
CustomPrismaModule.forRootAsync({
name: 'PrismaService',
useClass: ExtendedPrismaConfigService,
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Create the ExtendedPrismaConfigService
and extend it with the CustomPrismaClientFactory
and provide the type of your extended Prisma Client.
import { Injectable } from '@nestjs/common';
import { CustomPrismaClientFactory } from 'nestjs-prisma';
import {
type ExtendedPrismaClient,
extendedPrismaClient,
} from './prisma.extension';
@Injectable()
export class ExtendedPrismaConfigService
implements CustomPrismaClientFactory<ExtendedPrismaClient>
{
constructor() {
// TODO inject any other service here like the `ConfigService`
}
createPrismaClient(): ExtendedPrismaClient {
// you could pass options to your `PrismaClient` instance here
return extendedPrismaClient;
}
}
Use Extended Prisma Client
Inject CustomPrismaService
into your controller/service and use the extended Prisma Client for type-safety.
import { Inject, Injectable } from '@nestjs/common';
import { CustomPrismaService } from 'nestjs-prisma';
import { type ExtendedPrismaClient } from './prisma.extension';
@Injectable()
export class AppService {
constructor(
// ✅ use `ExtendedPrismaClient` type for correct type-safety of your extended PrismaClient
@Inject('PrismaService')
private prismaService: CustomPrismaService<ExtendedPrismaClient>,
) {}
users() {
return this.prismaService.client.user.findMany();
}
user(email: string) {
// 🦾 use new `findByEmail`
return this.prismaService.client.user.findByEmail(email);
}
}
Now you have access to your extensions this.prismaService.client.user.findByEmail(email)
.
Extension Packages
Follow these examples to use Prisma Extension packages in your NestJS application.
Pagination
Add pagination meta information to all or some Prisma models with Prisma Pagination Extension.
Install the pagination extension package.
npm i prisma-extension-pagination
Now add the pagination extension to your Prisma Client for all models.
// prisma.extension.ts
import { PrismaClient } from '@prisma/client';
import pagination from 'prisma-extension-pagination';
// pagination for all models
export const extendedPrismaClient = new PrismaClient().$extends(pagination());
export type ExtendedPrismaClient = typeof extendedPrismaClient;
Follow the docs to add pagination to specific models, if you don’t want to add pagination to all models.
Register your extended Prisma Client and use the new paginate
function for your Prisma models.
import { Inject, Injectable } from '@nestjs/common';
import { CustomPrismaService } from 'nestjs-prisma';
import { type ExtendedPrismaClient } from './prisma.extension';
@Injectable()
export class AppService {
constructor(
// ✅ use `ExtendedPrismaClient` from extension for correct type-safety
@Inject('PrismaService')
private prismaService: CustomPrismaService<ExtendedPrismaClient>,
) {}
async usersPage() {
// 🦾 use new `paginate` function
const [users, meta] = await this.prismaService.client.user
.paginate()
.withPages({
limit: 10,
page: 1,
includePageCount: true,
});
return {
users,
meta,
};
}
}
Read Replica
Add read replica support to your Prisma Client with Prisma Read Replica Extension.
Install the read replica extension package.
npm i @prisma/extension-read-replicas
Now add the read replica extension to your Prisma Client.
// prisma.extension.ts
import { PrismaClient } from '@prisma/client';
import { readReplicas } from '@prisma/extension-read-replicas';
export const extendedPrismaClient = new PrismaClient().$extends(
// update url to your read replica url
readReplicas({ url: 'postgresql://replica.example.com:5432/db' }),
);
export type ExtendedPrismaClient = typeof extendedPrismaClient;
Register your extended Prisma Client and while using CustomPrismaService
all read operations, such as findMany
, findUnique
are forwarded to a database replica. All write operations, such as create
, update
, delete
are forwarded to the primary database. To read from the primary database use $primary()
, instead of accessing a read replica.
import { Inject, Injectable } from '@nestjs/common';
import { CustomPrismaService } from 'nestjs-prisma';
import { type ExtendedPrismaClient } from './prisma.extension';
@Injectable()
export class AppService {
constructor(
// ✅ use `ExtendedPrismaClient` type for correct type-safety of your extended PrismaClient
@Inject('PrismaService')
private prismaService: CustomPrismaService<ExtendedPrismaClient>,
) {}
users() {
// uses database replica
return this.prismaService.client.user.findMany();
}
user(id: string) {
// bypasses database replica and uses primary database
return this.prismaService.client
.$primary()
.user.findUnique({ where: { id } });
}
add(email: string) {
// uses primary database
return this.prismaService.client.user.create({
data: {
email,
},
});
}
}
Enable preview feature (before version 4.16.0)
Enable clientExtensions
preview in your Prisma schema and generate Prisma Client again.
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
previewFeatures = ["clientExtensions"]
}
model User {
id String @id @default(cuid())
email String @unique
name String?
}
Type issues with Prisma Client v4.7.0
Change declaration
to false
in your tsconfig.json
- workaround for https://github.com/prisma/prisma/issues/16536#issuecomment-1332055501
The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.