PostgreSQL과 Next.js로 블로그를 만들면서 Prisma ORM을 처음 도입하게 되었습니다. MySQL을 주로 사용하던 입장에서 새로운 도구를 배우는 과정에서 겪은 시행착오와 해결 방법을 공유합니다.
Prisma가 뭔가요?
Prisma는 Node.js와 TypeScript를 위한 차세대 ORM(Object-Relational Mapping) 도구입니다. 기존의 SQL 쿼리를 직접 작성하는 방식에서 벗어나, 타입 안전성을 보장하면서도 직관적인 방식으로 데이터베이스를 다룰 수 있게 해줍니다.
왜 Prisma를 선택했나?
기존에 Laravel의 Eloquent ORM과 비슷하지만, TypeScript 지원이 훨씬 뛰어납니다:
- 타입 안전성: 데이터베이스 스키마에서 자동으로 TypeScript 타입 생성
- 직관적인 API: 복잡한 쿼리도 읽기 쉽게 작성
- 마이그레이션 자동화: 스키마 변경 이력 관리
- Prisma Studio: GUI로 데이터 확인 가능
프로젝트 설정
1. Prisma 설치
npm install prisma @prisma/client
npx prisma init
설치하면 프로젝트에 두 가지가 생성됩니다:
- prisma/schema.prisma: 데이터베이스 스키마 정의
- .env: 데이터베이스 연결 정보
2. 환경변수 로딩 설정
최신 Prisma 버전에서는 추가 설정이 필요할 수 있습니다:
npm install dotenv
프로젝트 루트에 prisma.config.ts 파일 생성:
import "dotenv/config";
⚠️ URL 인코딩 주의: 비밀번호에 특수문자가 있으면 인코딩이 필요합니다!
# → %23
@ → %40
: → %3A
예시:
# 비밀번호: pass#word
DATABASE_URL="postgresql://user:pass%23word@host:5432/db"
스키마 작성하기
prisma/schema.prisma 파일에서 데이터베이스 구조를 정의합니다. 간단한 블로그 예시:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
name String
posts Post[]
createdAt DateTime @default(now())
}
model Post {
id String @id @default(cuid())
title String
content String @db.Text
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
스키마 문법 이해하기
기본 어노테이션
- @id: 기본키(Primary Key)
- @unique: 중복 불가
- @default(): 기본값 설정
- @updatedAt: 수정 시 자동으로 현재 시간으로 업데이트
- ?: Optional, null 허용
관계(Relation) 설정
1:N 관계 (한 사용자가 여러 글 작성):
model User {
posts Post[] // 배열 = 여러 개
}
model Post {
author User @relation(fields: [authorId], references: [id])
authorId String // 외래키
}
양방향 관계를 명시해야 합니다. User.posts와 Post.author 둘 다 필요!
M:N 관계 (글 ↔ 태그):
model Post {
tags Tag[]
}
model Tag {
posts Post[]
}
Prisma가 자동으로 중간 테이블(_PostToTag)을 생성합니다.
Supabase 연결하기
무료 PostgreSQL 호스팅으로 Supabase를 사용했습니다.
Connection String 종류
Supabase는 두 가지 연결 방식을 제공합니다:
- Session Pooler (포트 5432)
- 세션 단위 연결 유지
- Migration 가능 ✅
- 일반적인 앱 실행에 적합
- Transaction Pooler (포트 6543)
- 트랜잭션 단위로 연결 교체
- 더 많은 동시 접속 처리
- Migration에는 부적합
권장 설정
Session Pooler만 사용하는 경우 (간단):
DATABASE_URL="postgresql://postgres.xxx:password@aws-0-ap-northeast-2.pooler.supabase.com:5432/postgres"
둘 다 사용하는 경우 (최적화):
# Transaction Pooler (앱 실행용)
DATABASE_URL="postgresql://postgres.xxx:password@aws-0-ap-northeast-2.pooler.supabase.com:6543/postgres?pgbouncer=true"
# Direct Connection (Migration용)
DIRECT_URL="postgresql://postgres:password@db.xxx.supabase.co:5432/postgres"
schema.prisma에 추가:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL") // 추가
}
블로그 규모라면 Session Pooler만으로도 충분합니다!
마이그레이션 실행
스키마 작성이 끝났으면 실제 데이터베이스에 테이블을 생성합니다:
npx prisma migrate dev --name init
--name init은 마이그레이션 이름입니다. Git commit 메시지처럼 의미있게 작성하세요:
npx prisma migrate dev --name add_tags
npx prisma migrate dev --name add_view_count
마이그레이션 파일
prisma/migrations/ 폴더에 SQL 파일이 자동 생성됩니다:
prisma/migrations/
└── 20250426123456_init/
└── migration.sql
이 파일들은 Git으로 관리되며, 팀원들과 데이터베이스 변경 이력을 공유할 수 있습니다.
Prisma Client 사용하기
마이그레이션 후 자동으로 생성된 Prisma Client로 데이터베이스 작업을 수행합니다.
Client 초기화
lib/prisma.ts 파일 생성:
import { PrismaClient } from '@prisma/client'
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined
}
export const prisma = globalForPrisma.prisma ?? new PrismaClient()
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
기본 CRUD 작업
Create (생성):
const post = await prisma.post.create({
data: {
title: '첫 번째 글',
content: '안녕하세요!',
slug: 'first-post',
author: {
connect: { id: userId }
}
}
})
Read (조회):
// 전체 조회
const posts = await prisma.post.findMany({
where: { published: true },
include: {
author: true,
tags: true
},
orderBy: { createdAt: 'desc' }
})
// 단일 조회
const post = await prisma.post.findUnique({
where: { slug: 'first-post' }
})
Update (수정):
const post = await prisma.post.update({
where: { id: postId },
data: {
title: '수정된 제목',
published: true
}
})
Delete (삭제):
await prisma.post.delete({
where: { id: postId }
})
유용한 도구: Prisma Studio
GUI로 데이터를 확인하고 수정할 수 있는 도구입니다:
npx prisma studio
http://localhost:5555에서 테이블 데이터를 시각적으로 관리할 수 있습니다.
마치며
Prisma의 강점
- TypeScript 타입 자동 생성으로 개발 경험 향상
- 마이그레이션 자동화로 스키마 변경 추적 용이
- 직관적인 API로 복잡한 관계도 쉽게 표현
- Prisma Studio로 빠른 데이터 확인 가능
주의할 점
- 특수문자 비밀번호는 URL 인코딩 필수
- Connection Pooler 설정 확인 (Session vs Transaction)
- 최신 버전에서는 prisma.config.ts 추가 필요
- 양방향 관계는 반드시 양쪽 모델에 명시
MySQL을 주로 사용하던 입장에서 PostgreSQL + Prisma 조합은 새로운 경험이었습니다. 특히 TypeScript와의 통합이 타입 안전성을 크게 높여주어 실수를 줄일 수 있었습니다.
참고 자료:
'개발 & IT > 백엔드' 카테고리의 다른 글
| Sequelize vs Prisma: Node.js ORM 비교 분석 (0) | 2025.10.26 |
|---|---|
| Let's Encrypt 인증서 자동 갱신 완벽 가이드 (1) | 2025.10.14 |
| nginx SSL 설정 중 만난 DNS 캐시 트러블슈팅 (0) | 2025.10.14 |
| apt autoremove란? 리눅스 패키지 관리의 숨은 조력자 (0) | 2025.10.10 |
| MySQL vs PostgreSQL, 뭘 선택해야 할까? 완벽 비교 가이드 (0) | 2025.09.29 |