dev_tools
Back to guides

NestJS + TypeScript + Prisma

Build a structured, enterprise-grade REST API with NestJS's module system, dependency injection, Prisma ORM, and PostgreSQL.

NestJS
TypeScript
Prisma
PostgreSQL
Node.js
1

Install the NestJS CLI

The NestJS CLI scaffolds the full project structure and generates modules, controllers, and services with a single command.

npm install -g @nestjs/cli
2

Create a New Project

Scaffold a new NestJS app. Choose npm when prompted (or your preferred package manager). The CLI sets up TypeScript, ESLint, Jest, and the full src/ structure automatically.

nest new my-nest-api
3

Install Prisma and Dependencies

Install Prisma as a dev dep, the Prisma Client as runtime, and class-validator + class-transformer for DTO validation.

npm install @prisma/client class-validator class-transformer && npm install -D prisma
4

Initialize Prisma

Generate the prisma/schema.prisma file and .env.

npx prisma init --datasource-provider postgresql
5

Define the Schema

Add a User model to prisma/schema.prisma.

prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
6

Run Migration

npx prisma migrate dev --name init
7

Create the PrismaService

NestJS uses dependency injection — wrap PrismaClient in an @Injectable() service so any module can import it. The onModuleInit hook opens the connection when the app starts.

src/prisma/prisma.service.ts
import { Injectable, OnModuleInit } from '@nestjs/common'
import { PrismaClient } from '@prisma/client'

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

Create the PrismaModule

Export PrismaService from its own module so any feature module can import it.

src/prisma/prisma.module.ts
import { Module } from '@nestjs/common'
import { PrismaService } from './prisma.service'

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

Generate the Users Resource

The CLI generates a complete users/ folder with module, controller, service, and DTOs.

nest generate resource users --no-spec
💡Choose 'REST API' when prompted, and 'Yes' for CRUD entry points.
10

Create the DTOs

DTOs define the shape of request bodies and are validated automatically by the ValidationPipe.

src/users/dto/create-user.dto.ts
import { IsEmail, IsOptional, IsString, MinLength } from 'class-validator'

export class CreateUserDto {
  @IsEmail()
  email: string

  @IsOptional()
  @IsString()
  @MinLength(2)
  name?: string
}
11

Implement the UsersService

Replace the generated stub with real Prisma queries.

src/users/users.service.ts
import { Injectable, NotFoundException } from '@nestjs/common'
import { PrismaService } from '../prisma/prisma.service'
import { CreateUserDto } from './dto/create-user.dto'

@Injectable()
export class UsersService {
  constructor(private readonly prisma: PrismaService) {}

  findAll() {
    return this.prisma.user.findMany({ orderBy: { createdAt: 'desc' } })
  }

  async findOne(id: number) {
    const user = await this.prisma.user.findUnique({ where: { id } })
    if (!user) throw new NotFoundException(`User #${id} not found`)
    return user
  }

  create(dto: CreateUserDto) {
    return this.prisma.user.create({ data: dto })
  }

  async remove(id: number) {
    await this.findOne(id)
    return this.prisma.user.delete({ where: { id } })
  }
}
12

Wire Up the Module and Enable Validation

Import PrismaModule in UsersModule, then enable ValidationPipe globally in main.ts so DTOs are validated on every request.

src/main.ts
import { NestFactory } from '@nestjs/core'
import { ValidationPipe } from '@nestjs/common'
import { AppModule } from './app.module'

async function bootstrap() {
  const app = await NestFactory.create(AppModule)

  app.useGlobalPipes(new ValidationPipe({
    whitelist:        true,   "text-muted-foreground italic">// strip unknown fields
    forbidNonWhitelisted: true,
    transform:        true,   "text-muted-foreground italic">// auto-cast params to correct types
  }))

  await app.listen(process.env.PORT ?? 3000)
  console.log(`Application running on port ${process.env.PORT ?? 3000}`)
}

bootstrap()
13

Start the Development Server

npm run start:dev
💡NestJS hot-reloads on save. Test with: `curl -X POST http://localhost:3000/users -H 'Content-Type: application/json' -d '{"email":"alice@example.com","name":"Alice"}'`

Found this guide helpful? Check out more tools and guides.

Browse All Guides