Enterprise-ready database for NestJS apps
Build high-performance and type-safe NestJS apps with Prisma's developer-friendly database tools: The world's most popular TypeScript ORM and the first serverless database without cold starts.
Why NestJS and Prisma?
Built for high-performance web apps
Built on unikernels, Prisma Postgres runs on bare metal servers for peak performance and infinite scalability.
Serverless, without cold starts
The first serverless database with pay-as-you-go pricing, no infrastructure management, and zero cold starts.
Built-in global caching
Add a cache strategy to any database query and its results will be cached close to your users for peak performance and UX.
TypeScript-first
Prisma ORM is the pioneer of type-safe ORMs. Paired with NestJS, it enables high productivity and confidence through strong typing.
Perfect for dependency injection
Prisma's service-based design fits naturally into NestJS's dependency injection system, making database access available throughout application modules.
Helpful communities
Both NestJS and Prisma have vibrant communities where you find support, fun events and amazing developers.
How Prisma Postgres and NestJS fit together
Prisma Postgres integrates perfectly with NestJS's dependency injection system and modular architecture. By creating a PrismaService that extends the PrismaClient, you can inject database access throughout your application.
NestJS's controller/service pattern pairs naturally with Prisma's type-safe queries, creating a clean separation between your API endpoints and database operations. Here's how you can implement GET and POST routes for users:
These routes will access the PrismaService as follows:
// src/prisma/prisma.service.ts
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaPg } from '@prisma/adapter-pg';
import { PrismaClient } from '../generated/client';
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
constructor() {
super({
adapter: new PrismaPg({
connectionString: process.env.DATABASE_URL,
}),
});
}
async onModuleInit() {
await this.$connect();
}
async onModuleDestroy() {
await this.$disconnect();
}
}
// src/users/users.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
@Post()
create(@Body() data: { name: string; email: string }) {
return this.usersService.create(data);
}
}
// src/users/users.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
@Injectable()
export class UsersService {
constructor(private prisma: PrismaService) {}
async findAll() {
return this.prisma.user.findMany();
}
async create(data: { name: string; email: string }) {
return this.prisma.user.create({ data });
}
}NestJS's Guard system provides the perfect place to integrate JWT authentication with Prisma Postgres. Instead of middleware, NestJS uses Guards to protect routes, and the dependency injection system makes it easy to incorporate Prisma for user lookups. This pattern follows NestJS's decorator-driven approach while leveraging Prisma's type-safe queries for secure user verification.
This guard can then be used inside your controller to protect specific routes:
// src/auth/jwt.guard.ts
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { PrismaService } from '../prisma/prisma.service';
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(
private jwtService: JwtService,
private prisma: PrismaService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
if (!token) throw new UnauthorizedException();
try {
const payload = this.jwtService.verify(token);
const user = await this.prisma.user.findUnique({
where: { id: payload.userId },
select: { id: true, email: true, role: true }
});
if (!user) throw new UnauthorizedException();
request.user = user;
return true;
} catch {
throw new UnauthorizedException();
}
}
private extractTokenFromHeader(request): string | undefined {
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
}
}
// src/users/users.controller.ts
import { Controller, Get, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from '../auth/jwt.guard';
import { User } from '../decorators/user.decorator';
@Controller('users')
export class UsersController {
@Get('profile')
@UseGuards(JwtAuthGuard)
getProfile(@User() user) {
return user;
}
}NestJS's service layer is the ideal place to implement transaction logic with Prisma Postgres. By encapsulating complex database operations in service methods, you maintain clean controllers while ensuring data integrity.
Prisma's transaction API integrates smoothly with NestJS's asynchronous architecture, allowing you to perform multiple database operations as a single atomic unit while following NestJS's best practices.
Here is how you call the transaction from a controller:
// src/orders/orders.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
@Injectable()
export class OrdersService {
constructor(private prisma: PrismaService) {}
async createOrder(data: { userId: number; items: any[] }) {
const { userId, items } = data;
return this.prisma.$transaction(async (tx) => {
const order = await tx.order.create({
data: { userId, status: 'PENDING' }
});
const orderItems = await Promise.all(
items.map(item => tx.orderItem.create({
data: { orderId: order.id, productId: item.productId, quantity: item.quantity }
}))
);
return { order, orderItems };
});
}
}
// src/orders/orders.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { OrdersService } from './orders.service';
@Controller('orders')
export class OrdersController {
constructor(private ordersService: OrdersService) {}
@Post()
createOrder(@Body() data: { userId: number; items: any[] }) {
return this.ordersService.createOrder(data);
}
}When using Prisma Postgres, you can use the Prisma schema to model your data in a declarative way and auto-generate migration files to make changes to your database schema. The following data model will be mapped to User and Post tables in the database:
Using Prisma Migrate, you can generate a (customizable) SQL migration file that will execute the required changes against the database.
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User? @relation(fields: [authorId], references: [id])
authorId Int?
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}Featured Prisma & NestJS community examples
Production-ready starter kit with NestJS & Prisma
A starter kit covering everything you need to build NestJS with Prisma in production.
Prisma in the NestJS docs
Learn how to use Prisma with NestJS in the official NestJS documentation.
nestjs-prisma module for seamlessly integrating NestJS & Prisma
This npm library helps you integrate Prisma ORM in NestJS applications. Its PrismaModule gives access to a PrismaService which you can use via dependency injection in your controller, resolver, services, guards and more.
Building a REST API with NestJS and Prisma
A comprehensive tutorial series about building a NestJS REST API with Prisma.
Migrating a large production app from TypeORM to Prisma
An in-depth article about the migration process of a NestJS app from TypeORM to Prisma.