NestJS — Enterprise Node.js

Prisma with NestJS

16 min Lesson 24 of 30

Prisma with NestJS

TypeORM is not the only option. Prisma is a modern, type-safe ORM that many teams prefer for its excellent TypeScript experience and a single, readable schema file. NestJS works with Prisma cleanly — you wrap the Prisma client in an injectable service.

How Prisma differs from TypeORM

  • Schema-first: you define models in one schema.prisma file, not in scattered entity classes.
  • Generated client: Prisma generates a fully-typed client from that schema — autocomplete and type-checking on every query.
  • Explicit queries: no lazy loading or hidden magic; you ask for exactly the data you want.

The Prisma schema

Models and relations live in one declarative file:

// schema.prisma model User { id Int @id @default(autoincrement()) email String @unique name String posts Post[] } model Post { id Int @id @default(autoincrement()) title String author User @relation(fields: [authorId], references: [id]) authorId Int }

Running npx prisma generate produces the typed client; npx prisma migrate dev creates and applies a migration from the schema.

Wrapping Prisma in a NestJS service

The idiomatic integration is a PrismaService that extends PrismaClient and connects on module init:

import { Injectable, OnModuleInit } from '@nestjs/common'; import { PrismaClient } from '@prisma/client'; @Injectable() export class PrismaService extends PrismaClient implements OnModuleInit { async onModuleInit() { await this.$connect(); } }

Notice how the lifecycle hook from earlier (onModuleInit) is exactly the right place to open the connection.

Using it in a feature service

import { Injectable } from '@nestjs/common'; import { PrismaService } from './prisma.service'; @Injectable() export class UsersService { constructor(private prisma: PrismaService) {} findAll() { return this.prisma.user.findMany({ include: { posts: true } }); } create(data: { email: string; name: string }) { return this.prisma.user.create({ data }); } }
Prisma's type safety is its superpower. Every query result is typed from the schema, so a typo in a field name or a wrong shape is a compile-time error — not a runtime surprise. The editor autocompletes relations, filters, and selects.

Transactions in Prisma

Prisma offers transactions too, via $transaction() — either an array of operations or an interactive callback like TypeORM's:

await this.prisma.$transaction(async (tx) => { await tx.account.update({ where: { id: from }, data: { balance: { decrement: amount } } }); await tx.account.update({ where: { id: to }, data: { balance: { increment: amount } } }); });
TypeORM or Prisma? Both are excellent. TypeORM is decorator/class-based and feels native to NestJS conventions; Prisma offers stronger end-to-end type safety and a single schema file. Choose one per project and stay consistent — they are not mixed.

Summary

Prisma is a schema-first, type-safe alternative to TypeORM. Define models in schema.prisma, generate the typed client, and integrate it by wrapping PrismaClient in a PrismaService that connects in onModuleInit. Query with fully-typed methods like findMany/create, and use $transaction() for atomicity. Next: working with a NoSQL database, MongoDB.