Node.js 프로젝트에 Prisma 마이그레이션 도입 후기

배경

사내 API 서버가 TypeORM을 사용 중이었는데, 복잡한 관계 설정과 런타임 에러가 잦아 Prisma 2로 전환을 결정했다. 특히 타입 추론이 제대로 안 되는 부분이 많아 개발 생산성이 떨어지고 있었다.

마이그레이션 과정

1. 스키마 변환

기존 TypeORM 엔티티를 Prisma Schema로 변환했다. prisma db pull로 기존 DB를 introspect한 뒤 수동으로 관계를 정리했다.

model User {
  id        String   @id @default(uuid())
  email     String   @unique
  posts     Post[]
  createdAt DateTime @default(now())
}

model Post {
  id       String @id @default(uuid())
  title    String
  author   User   @relation(fields: [authorId], references: [id])
  authorId String
}

2. 쿼리 변환

TypeORM의 QueryBuilder 패턴을 Prisma의 fluent API로 변환했다. 복잡한 조인 쿼리가 오히려 더 간결해졌다.

// Before (TypeORM)
const posts = await postRepository
  .createQueryBuilder('post')
  .leftJoinAndSelect('post.author', 'author')
  .where('author.id = :id', { id })
  .getMany();

// After (Prisma)
const posts = await prisma.post.findMany({
  where: { authorId: id },
  include: { author: true }
});

3. 트랜잭션 처리

TypeORM의 @Transaction 데코레이터 대신 Prisma의 $transaction을 사용했다. 더 명시적이고 에러 핸들링이 쉬워졌다.

await prisma.$transaction(async (tx) => {
  const user = await tx.user.create({ data: userData });
  await tx.post.create({ data: { ...postData, authorId: user.id } });
});

결과

  • 타입 안정성: Prisma Client가 생성하는 타입 덕분에 런타임 에러가 80% 감소
  • 쿼리 성능: N+1 문제를 include로 쉽게 해결
  • DX 개선: VSCode 자동완성이 완벽하게 동작

아쉬운 점

  • 복잡한 raw 쿼리는 여전히 $queryRaw 사용 필요
  • 마이그레이션 파일이 SQL로 생성되어 멀티 DB 지원 시 주의 필요

전체적으로 만족스러운 마이그레이션이었다. 다음 프로젝트에서도 Prisma를 우선 고려할 예정이다.