15.1 Prisma 소개 — TypeScript ORM의 표준
Prisma란?
Prisma는 TypeScript 기반의 차세대 ORM(Object-Relational Mapper)입니다. 스키마 파일로 데이터 모델을 정의하면 타입 안전한 클라이언트를 자동 생성합니다.
Prisma 구성:
- Prisma Schema: 데이터 모델 정의 (.prisma 파일)
- Prisma Client: 자동 생성된 타입 안전 쿼리 빌더
- Prisma Migrate: 스키마 기반 DB 마이그레이션
- Prisma Studio: 데이터 시각화 GUI
설치 및 초기화
npm install prisma @prisma/client
npx prisma init # prisma/schema.prisma 와 .env 생성
환경 변수 설정
# .env
DATABASE_URL="postgresql://user:password@localhost:5432/mydb?schema=public"
기본 스키마 작성
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql" // mysql, sqlite, mongodb 등
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
profile Profile?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
tags Tag[]
createdAt DateTime @default(now())
}
model Profile {
id Int @id @default(autoincrement())
bio String?
user User @relation(fields: [userId], references: [id])
userId Int @unique
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
posts Post[]
}
마이그레이션 실행
# 마이그레이션 생성 및 적용
npx prisma migrate dev --name init
# 프로덕션 마이그레이션 적용
npx prisma migrate deploy
# Prisma Client 재생성 (스키마 변경 후)
npx prisma generate
# Prisma Studio 실행
npx prisma studio
Prisma Client 기본 사용
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
// 연결은 자동 관리됨
// 사용자 생성
const user = await prisma.user.create({
data: {
email: 'alice@example.com',
name: 'Alice',
},
})
console.log(user)
// { id: 1, email: 'alice@example.com', name: 'Alice', ... }
}
main()
.catch(console.error)
.finally(async () => {
await prisma.$disconnect()
})
필드 타입 참조
model Example {
// 기본 타입
id Int @id @default(autoincrement())
uuid String @id @default(uuid())
cuid String @id @default(cuid())
// 스칼라 타입
name String
age Int
score Float
isActive Boolean @default(true)
data Json
bytes Bytes
createdAt DateTime @default(now())
// 선택적 필드
bio String?
// 기본값
role Role @default(USER)
count Int @default(0)
// 인덱스
@@index([name])
@@unique([email, tenantId])
}
enum Role {
ADMIN
USER
GUEST
}
고수 팁
Prisma 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({
log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
})
// 개발 환경에서 핫 리로드 시 연결 누수 방지
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma
}
Prisma Accelerate (엣지 캐싱)
import { PrismaClient } from '@prisma/client/edge'
import { withAccelerate } from '@prisma/extension-accelerate'
const prisma = new PrismaClient().$extends(withAccelerate())
// 캐시 TTL 설정
const users = await prisma.user.findMany({
cacheStrategy: { ttl: 60 }, // 60초 캐시
})