Skip to content

NestJS Prisma

Prisma generates a typed client from a schema file and fits NestJS through a dedicated injectable service. This lesson shows the standard Nest + Prisma wiring.

PrismaService as a Nest Provider

Prisma is not wrapped by an official Nest module the way TypeORM is. The common pattern is a PrismaService that extends PrismaClient, connects on module init, and is exported from a global database module.

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
  async onModuleInit() {
    await this.$connect();
  }

  async onModuleDestroy() {
    await this.$disconnect();
  }
}

Lifecycle hooks ensure Prisma connects once when Nest starts and disconnects cleanly on shutdown.

Schema Model and Query Example

// schema.prisma
model User {
  id    Int    @id @default(autoincrement())
  email String @unique
}

// users.service.ts
const user = await this.prisma.user.create({
  data: { email: dto.email },
});
  • Run npx prisma migrate dev to apply schema changes locally.
  • Run npx prisma generate after schema edits so the TypeScript client updates.
  • Inject PrismaService into feature services rather than constructing PrismaClient repeatedly.
  • Use $transaction for multi-step writes that must succeed or fail together.

Prisma Nest Cheatsheet

Commands and APIs you will use constantly.

Item Purpose
schema.prisma Source of truth for models and datasources
prisma migrate Create and apply SQL migrations
prisma generate Regenerate the typed client
prisma.user.findMany() Type-safe query through PrismaService
$transaction([...]) Run multiple writes atomically

Global Prisma Module

Mark a PrismaModule as @Global() and export PrismaService so every feature module can inject it without re-importing. Keep direct Prisma access out of controllers.

@Global()
@Module({
  providers: [PrismaService],
  exports: [PrismaService],
})
export class PrismaModule {}

DTOs vs Generated Prisma Types

Do not expose Prisma input types directly as HTTP DTOs. Keep class-validator DTOs at the boundary and map to Prisma create/update inputs inside services.

Common Mistakes

  • Creating a new PrismaClient instance in every service instead of a shared provider.
  • Committing credentials in schema.prisma instead of using env("DATABASE_URL").
  • Forgetting to regenerate the client after schema changes.
  • Passing unvalidated request bodies straight into Prisma create calls.

Key Takeaways

  • Wrap PrismaClient in a Nest PrismaService with connect/disconnect lifecycle hooks.
  • Export PrismaService from a (often global) module for DI across features.
  • Prisma schema + migrate + generate is the source of database types.
  • Keep HTTP DTOs separate from Prisma generated input types.

Pro Tip

Add PrismaClient extension hooks later for soft deletes or multi-tenancy filters rather than duplicating the same where clause in every query.