DEV Community

Yogesh Prasad
Yogesh Prasad

Posted on

NestJS Expert Series (Part 2): Database Integration with Prisma & TypeORM

Welcome back to the NestJS Expert Series! 🎉
In Part 1,we built a simple CRUD API using NestJS fundamentals—Modules, Controllers, and Services.

But any real-world application needs persistent storage. That’s where databases come in.

In this article, we’ll integrate databases with NestJS using two popular ORMs:

Prisma – Modern, type-safe ORM with great DX.

TypeORM – Mature ORM used widely in enterprise projects.

By the end, you’ll be able to hook up your NestJS app to a PostgreSQL database (the same steps apply for MySQL or SQLite).

⚡ Step 1: Setting Up a Database

For this guide, let’s use PostgreSQL. If you have Docker installed:

docker run --name nest-postgres -e POSTGRES_PASSWORD=admin -e POSTGRES_USER=admin -e POSTGRES_DB=tasks -p 5432:5432 -d postgres

📦 Step 2: Adding Prisma to NestJS
npm install prisma --save-dev
npm install @prisma/client
npx prisma init

This creates a prisma/schema.prisma file. Define a simple Task model:

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

generator client {
  provider = "prisma-client-js"
}

model Task {
  id        Int      @id @default(autoincrement())
  title     String
  isCompleted Boolean @default(false)
  createdAt DateTime @default(now())
}

Enter fullscreen mode Exit fullscreen mode

Run migrations:

npx prisma migrate dev --name init

🛠️ Step 3: Using Prisma in NestJS

`Create a Prisma service:

nest g service prisma`
Enter fullscreen mode Exit fullscreen mode

prisma.service.ts:

import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

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


Enter fullscreen mode Exit fullscreen mode

Now inject it into your TasksService:

import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';

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

  findAll() {
    return this.prisma.task.findMany();
  }

  create(title: string) {
    return this.prisma.task.create({ data: { title } });
  }

  update(id: number, isCompleted: boolean) {
    return this.prisma.task.update({
      where: { id },
      data: { isCompleted },
    });
  }

  delete(id: number) {
    return this.prisma.task.delete({ where: { id } });
  }
}
Enter fullscreen mode Exit fullscreen mode

Now your Tasks API is connected to PostgreSQL with Prisma 🎉.

🔄 Alternative: TypeORM with NestJS

Some teams still prefer TypeORM for its flexibility. Here’s the quick setup:

npm install @nestjs/typeorm typeorm pg

Add it to app.module.ts:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Task } from './tasks/task.entity';
import { TasksModule } from './tasks/tasks.module';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'localhost',
      port: 5432,
      username: 'admin',
      password: 'admin',
      database: 'tasks',
      entities: [Task],
      synchronize: true,
    }),
    TasksModule,
  ],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

task.entity.ts:

import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity()
export class Task {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column({ default: false })
  isCompleted: boolean;
}


Enter fullscreen mode Exit fullscreen mode

Inject repositories with @InjectRepository(Task) in your services.

🚀 Conclusion

Prisma gives you type safety and an amazing developer experience.

TypeORM is feature-rich and widely adopted.

👉 Choose Prisma if you want speed + DX.
👉 Choose TypeORM if you need complex queries and legacy support.

Now your NestJS app can persist data into a database like a real-world backend.

In the next part of the series, we’ll tackle Authentication & Authorization with JWTs and Guards.

💡 Found this useful? Drop a ❤️ on Dev.to and follow me for Part 3 of the NestJS Expert Series.

Top comments (0)