
NestJS 프로젝트에서 Prisma를 효과적으로 사용하려면, NestJS의 핵심 개념인 모듈(Module)과 의존성 주입(Dependency Injection, DI) 시스템에 Prisma Client를 통합해야 합니다. 이 과정은 데이터베이스 연결을 관리하고 애플리케이션 전체에서 타입 안전한 Prisma Client를 사용할 수 있게 해줍니다.
2.1. Prisma Client를 래핑하는 PrismaService 생성
Prisma Client는 일반적인 라이브러리 객체입니다. 이를 NestJS의 DI 컨테이너에서 관리하고 생명주기를 제어하기 위해 NestJS 서비스(Service)로 래핑해야 합니다.
src/prisma/prisma.service.ts 파일을 생성합니다.
// src/prisma/prisma.service.ts
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
// 💡 PrismaClient를 상속하여 서비스 내에서 모든 Prisma 쿼리 메서드를 직접 사용할 수 있게 합니다.
export class PrismaService extends PrismaClient implements OnModuleInit {
// 생성자: PrismaClient를 초기화합니다.
constructor() {
super({
// 쿼리 로그를 활성화하여 개발 시 어떤 SQL이 실행되는지 확인 가능합니다.
log: ['query', 'error', 'warn'],
});
}
// 🛠️ OnModuleInit 구현
async onModuleInit() {
// NestJS 앱이 시작될 때 데이터베이스에 연결을 시도합니다.
await this.$connect();
}
// 🛠️ 선택 사항: 종료 훅을 설정하여 애플리케이션 종료 시 연결을 끊습니다.
// 이 메서드는 NestJS의 Lifecycle Hook을 활용하여 수동으로 호출해야 할 수도 있습니다.
async enableShutdownHooks(app: INestApplication) {
// NestJS가 'beforeExit' 시그널을 수신하면 데이터베이스 연결을 끊습니다.
this.$on('beforeExit', async () => {
await app.close();
});
}
}
2.2. 모듈 초기화 및 연결 관리
NestJS의 라이프사이클 훅(Lifecycle Hooks)을 사용하여 데이터베이스 연결의 생명주기를 관리합니다.
🔗 연결 ($connect()) - OnModuleInit 활용
- PrismaService가 OnModuleInit 인터페이스를 구현하고 있으므로, NestJS 애플리케이션이 초기화되는 시점(onModuleInit 메서드)에 Prisma Client의 $connect() 메서드를 호출하여 데이터베이스 연결을 설정합니다.
🚪 종료 ($disconnect()) - 종료 훅 활용
- Prisma Client는 일반적으로 연결 풀을 자동으로 관리합니다. 그러나 애플리케이션이 완전히 종료될 때 $disconnect()를 호출하여 열려있는 연결을 깨끗하게 정리하는 것이 좋습니다.
- 위의 PrismaService 코드에서 enableShutdownHooks 메서드를 정의하여 NestJS의 종료 시그널(beforeExit)을 감지하고 연결을 끊도록 설정했습니다. 이 훅은 메인 모듈에서 설정해야 합니다.
2.3. 의존성 주입(DI)으로 PrismaService 사용하기
Prisma Client를 서비스화했으므로, 이제 이를 NestJS 모듈 시스템에 등록하고 다른 서비스에 주입하여 사용합니다.
🧱 1단계: PrismaModule 생성 및 등록
별도의 PrismaModule을 생성하여 PrismaService를 외부로 제공(export)하도록 구성합니다.
// src/prisma/prisma.module.ts
import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
@Module({
providers: [PrismaService], // PrismaService를 이 모듈의 제공자(provider)로 등록
exports: [PrismaService], // 외부 모듈에서 사용할 수 있도록 export
})
export class PrismaModule {}
💉 2단계: 서비스/컨트롤러에 주입하여 사용하기
PrismaModule을 사용하려는 다른 모듈(예: AppModule 또는 UsersModule)의 imports 배열에 추가합니다.
A. AppModule에 PrismaModule 통합
// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PrismaModule } from './prisma/prisma.module'; // ⭐️ Import
@Module({
imports: [PrismaModule], // ⭐️ PrismaModule 등록
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
B. AppService에서 PrismaService 사용
이제 NestJS의 생성자 주입(Constructor Injection)을 통해 PrismaService를 사용합니다. 이로써 서비스 내에서 타입이 보장된 모든 Prisma 쿼리 메서드를 사용할 수 있습니다.
// src/app.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from './prisma/prisma.service'; // ⭐️ Import
@Injectable()
export class AppService {
// 💡 생성자 주입
constructor(private readonly prisma: PrismaService) {}
async createUser(name: string, email: string) {
// ⭐️ 타입 안전한 Prisma Client 메서드를 사용
return this.prisma.user.create({
data: {
name,
email,
},
});
}
async getUsers() {
return this.prisma.user.findMany();
}
getHello(): string {
return 'Hello World!';
}
}
이 구조를 통해 NestJS 앱의 생명주기 관리 하에 Prisma Client를 안전하고 타입 안전하게 사용할 수 있으며, 이는 클린 아키텍처와 높은 개발 생산성으로 이어집니다.
'Nest.js를 배워보자 > 15. NestJS & Prisma 완벽 가이드' 카테고리의 다른 글
| 🛡️ 5부. 고급 활용 및 데이터 무결성 (0) | 2025.12.03 |
|---|---|
| 🌐 4부. 관계형 데이터 쿼리 마스터하기 (0) | 2025.12.03 |
| 🔍 3부. CRUD 기본 및 복합 쿼리 (0) | 2025.12.03 |
| 🚀 1부.NestJS와 Prisma로 ORM 끝판왕 되기: 소개 및 기본 설정 (3) | 2025.12.03 |
| 📝 NestJS & Prisma 완벽 가이드 시리즈 목차 (0) | 2025.12.03 |