Prisma ORM 설정 가이드 (TypeScript 환경)
목표: TypeScript 프로젝트에서 Prisma ORM을 사용하여 데이터베이스와 상호작용할 수 있도록 설정합니다.
사전 준비:
- Node.js (LTS 버전 권장) 및 npm/yarn 설치
- TypeScript 프로젝트 (새로운 프로젝트 생성 또는 기존 프로젝트 사용)
- 사용할 관계형 데이터베이스 (예: PostgreSQL, MySQL, SQLite)가 설치되어 있거나 접근 가능한 상태여야 합니다.
1단계: Prisma 패키지 설치
먼저 프로젝트에 Prisma CLI 도구와 Prisma Client 라이브러리를 설치합니다. @prisma/client
는 데이터베이스와 상호작용하는 데 사용되는 타입 안전한 쿼리 빌더이며, prisma
는 CLI 도구입니다.
npm install prisma @prisma/client
# 또는
yarn add prisma @prisma/client
2단계: Prisma 초기화
Prisma CLI를 사용하여 프로젝트에 Prisma를 초기화합니다. 이 명령은 prisma
디렉토리를 생성하고 그 안에 schema.prisma
파일을 만듭니다. 또한, 데이터베이스 연결 정보를 위한 .env
파일을 자동으로 생성하거나 업데이트합니다.
npx prisma init
이 명령을 실행하면 프로젝트 루트에 다음 파일 및 디렉토리가 생성됩니다:
prisma/
: Prisma 관련 파일들을 저장하는 디렉토리prisma/schema.prisma
: Prisma 스키마를 정의하는 핵심 파일
.env
: 환경 변수를 관리하는 파일 (특히DATABASE_URL
이 추가됩니다)
3단계: .env
파일 설정 (데이터베이스 연결)
.env
파일을 열고 DATABASE_URL
환경 변수를 실제 데이터베이스 연결 문자열로 설정합니다. 이 문자열은 Prisma가 데이터베이스에 연결하는 데 사용됩니다.
예시 (PostgreSQL):
# .env 파일
DATABASE_URL="postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=public"
예시 (SQLite):
# .env 파일 (development.db 파일이 프로젝트 루트에 생성됨)
DATABASE_URL="file:./dev.db"
예시 (MySQL):
# .env 파일
DATABASE_URL="mysql://USER:PASSWORD@HOST:PORT/DATABASE"
중요: USER
, PASSWORD
, HOST
, PORT
, DATABASE
를 사용하려는 데이터베이스의 실제 정보로 교체해야 합니다.
4단계: schema.prisma
파일 정의 (데이터 모델 및 설정)
prisma/schema.prisma
파일을 열고 다음과 같이 설정합니다.
datasource
: 사용할 데이터베이스의provider
와url
을 지정합니다.url
은.env
파일의DATABASE_URL
을 참조합니다.generator
:prisma-client-js
를 사용하여 TypeScript를 지원하는 Prisma Client를 생성하도록 설정합니다.model
: 애플리케이션에서 사용할 데이터 모델(테이블)을 정의합니다. 각 모델은 데이터베이스 테이블에 매핑됩니다.
// prisma/schema.prisma
// 데이터베이스 설정
datasource db {
provider = "postgresql" // 사용하는 데이터베이스 종류 (예: "mysql", "sqlite", "sqlserver")
url = env("DATABASE_URL") // .env 파일의 DATABASE_URL 환경 변수 참조
}
// Prisma Client 생성기 설정
// TypeScript 환경에서 강력한 타입 지원을 위해 필수
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"] // 선택 사항: 최신 기능 미리보기 (필요 시 추가)
}
// 예시 데이터 모델: User
// 이 모델은 데이터베이스의 'User' 테이블에 해당합니다.
model User {
id String @id @default(uuid()) // Primary Key, UUID로 자동 생성
email String @unique // 이메일은 중복될 수 없음
name String? // 이름 (선택 사항, nullable)
age Int @default(0) // 기본값 설정
createdAt DateTime @default(now()) // 생성 시간 (기본값: 현재 타임스탬프)
updatedAt DateTime @updatedAt // 업데이트 시간 (변경 시 자동 업데이트)
posts Post[] // User와 Post 간의 1:N 관계 (Post 모델의 author 필드와 연결됨)
}
// 예시 데이터 모델: Post
model Post {
id String @id @default(uuid())
title String
content String?
published Boolean @default(false)
// User 모델과의 관계 정의
author User @relation(fields: [authorId], references: [id])
authorId String // 외래 키 (User 모델의 id 필드와 연결)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
TypeScript 추가 사항:generator client
블록의 provider = "prisma-client-js"
설정이 TypeScript를 위한 핵심입니다. 이 설정 덕분에 Prisma Client가 생성될 때 모델에 대한 완벽한 TypeScript 타입 정의가 포함되어, 코드 작성 시 강력한 타입 검사 및 자동 완성 기능을 활용할 수 있습니다.
5단계: 데이터베이스 마이그레이션
schema.prisma
파일에 정의된 데이터 모델을 기반으로 실제 데이터베이스에 스키마를 생성하거나 변경 사항을 적용합니다.
npx prisma migrate dev --name initial_migration
migrate dev
: 개발 환경에서 스키마 변경 사항을 관리하고 데이터베이스에 적용하는 명령입니다.--name initial_migration
: 생성될 마이그레이션 파일의 이름을 지정합니다. (처음이라면initial_migration
이나init
등으로 명명합니다.)- 이 명령을 실행하면
prisma/migrations
디렉토리가 생성되고, 그 안에 현재 스키마 상태를 반영하는 SQL 마이그레이션 파일이 생성됩니다. 또한, 자동으로 Prisma Client를 다시 생성합니다.
스키마 변경 시:schema.prisma
파일에 모델을 추가하거나, 기존 모델을 수정(필드 추가/삭제/타입 변경 등)할 때마다 이 명령을 다시 실행해야 합니다. Prisma는 변경 사항을 감지하여 새로운 마이그레이션 파일을 생성하고 데이터베이스에 적용합니다.
6단계: Prisma Client 생성 (선택 사항이지만 권장)
npx prisma migrate dev
명령은 마이그레이션 후에 자동으로 npx prisma generate
를 실행합니다. 하지만, 스키마를 변경하지 않고 단순히 Prisma Client만 다시 생성하고 싶을 때 이 명령을 수동으로 실행할 수 있습니다.
npx prisma generate
이 명령은 node_modules/.prisma/client
경로에 @prisma/client
패키지를 재생성합니다. 이 패키지에는 정의된 모델에 대한 TypeScript 타입 정의와 쿼리 빌더가 포함됩니다.
7단계: 애플리케이션 코드에서 Prisma Client 사용
이제 TypeScript 코드에서 Prisma Client를 사용하여 데이터베이스와 상호작용할 수 있습니다.
Prisma Client 인스턴스 관리 (Singleton 패턴 권장):
개발 환경에서 핫 리로딩 등으로 인해 Prisma Client 인스턴스가 여러 개 생성되는 것을 방지하기 위해, 싱글톤 패턴으로 Prisma Client 인스턴스를 관리하는 것이 좋습니다.
예를 들어, src/lib/prisma.ts
(또는 src/utils/prisma.ts
) 파일을 생성합니다:
// src/lib/prisma.ts
import { PrismaClient } from '@prisma/client';
// TypeScript에서 전역 변수 선언을 위한 모듈 증대 (Declaration Merging)
// 이 부분이 TypeScript의 전역 타입 스코프에 `prisma` 변수를 추가하여,
// 다른 파일에서 `global.prisma`를 사용할 때 타입 오류가 발생하지 않도록 합니다.
declare global {
// `var` 키워드를 사용하여 전역 스코프에 변수를 선언합니다.
var prisma: PrismaClient | undefined;
}
let prisma: PrismaClient;
// 프로덕션 환경에서는 새로운 PrismaClient 인스턴스를 생성
if (process.env.NODE_ENV === 'production') {
prisma = new PrismaClient();
} else {
// 개발 환경에서는 전역 변수를 사용하여 기존 인스턴스가 있으면 재사용
// 핫 리로딩 시 PrismaClient 인스턴스가 계속 생성되는 것을 방지
if (!global.prisma) {
global.prisma = new PrismaClient();
}
prisma = global.prisma;
}
export default prisma;
애플리케이션 코드에서 Prisma Client 사용 예시:
// 예를 들어, API 핸들러, 서비스 레이어 등에서 사용
import prisma from './lib/prisma'; // 위에서 정의한 prisma 인스턴스 임포트
async function createUser(email: string, name?: string) {
try {
const newUser = await prisma.user.create({
data: {
email,
name,
},
});
console.log('Created user:', newUser);
return newUser;
} catch (error) {
console.error('Error creating user:', error);
throw error;
} finally {
// 연결 풀을 사용하는 경우 일반적으로 close()를 명시적으로 호출할 필요는 없지만,
// 필요에 따라 연결을 종료할 수 있습니다.
// await prisma.$disconnect();
}
}
async function findUsers() {
try {
// Prisma Client는 강력한 타입 추론을 제공합니다.
// users는 자동으로 `User[]` 타입으로 추론됩니다.
const users = await prisma.user.findMany({
where: {
// 필터링 조건
age: {
gt: 18 // age가 18보다 큰 사용자
}
},
orderBy: {
createdAt: 'desc' // 최신 생성 순으로 정렬
},
select: {
id: true,
email: true,
name: true,
posts: { // 관계된 Post 데이터도 함께 조회
select: {
title: true,
published: true
}
}
}
});
console.log('Found users:', users);
return users;
} catch (error) {
console.error('Error finding users:', error);
throw error;
}
}
// 예시 함수 호출
async function main() {
await createUser('test@example.com', 'Test User');
await findUsers();
}
main()
.catch(e => {
console.error(e);
process.exit(1);
})
.finally(async () => {
// 애플리케이션 종료 시 데이터베이스 연결 해제
await prisma.$disconnect();
});
TypeScript의 이점:
- 자동 완성 및 타입 검사:
prisma.user.create()
나prisma.user.findMany()
와 같은 메서드를 호출할 때, Prisma Client는schema.prisma
에 정의된 모델을 기반으로 정확한 필드 이름, 타입, 관계 등에 대한 자동 완성 및 타입 검사를 제공합니다. 예를 들어,data
객체에 존재하지 않는 필드를 입력하면 컴파일 타임에 오류가 발생합니다. - 런타임 오류 감소: 잘못된 쿼리나 존재하지 않는 필드 참조로 인한 런타임 오류를 TypeScript의 타입 시스템으로 미리 방지할 수 있습니다.
- 코드 가독성 향상: 데이터베이스 스키마와 애플리케이션 코드 간의 명확한 연결을 제공하여 코드의 가독성과 유지보수성을 높입니다.
추가 팁:
- Prisma Studio:
npx prisma studio
명령을 실행하여 데이터베이스의 데이터를 시각적으로 확인하고 편집할 수 있는 GUI 도구를 실행하세요. 개발 및 디버깅에 매우 유용합니다. - 환경 변수 보안:
.env
파일은.gitignore
에 추가하여 버전 관리에서 제외하는 것이 필수적입니다. 프로덕션 환경에서는 호스팅 서비스의 환경 변수 관리 시스템을 사용해야 합니다. - 배포 시 마이그레이션: 프로덕션 환경에 배포할 때는 마이그레이션이 올바르게 실행되도록 설정해야 합니다. 보통 CI/CD 파이프라인에서
npx prisma migrate deploy
명령을 사용하여 적용합니다. - 관계형 데이터베이스 이해: Prisma ORM을 효과적으로 사용하려면 관계형 데이터베이스의 기본 개념(테이블, 필드, 관계 등)을 이해하고 있는 것이 좋습니다.
이 단계들을 따르면 TypeScript 프로젝트에서 Prisma ORM을 성공적으로 설정하고 사용할 수 있습니다.