개인 포트폴리오 사이트를 Next.js로 제작하던 중, 프로젝트/활동 등의 정보를 상수 파일에 직접 추가하는 대신 데이터베이스에 저장하여 쉽게 추가/삭제/수정할 수 있도록 ORM을 도입하기로 했습니다.
유명한 ORM들(Prisma, TypeORM, Sequelize) 중에서 Prisma를 선택한 이유는 npm 사용 그래프가 가파르게 상승하는 핫한 라이브러리이기도 하고, 아래와 같이 직관적인 인터페이스를 제공하여 개발 생산성을 높일 수 있을 것 같았기 때문입니다.

먼저 아래 명령어로 Prisma 기본 설정을 진행합니다.
pnpm add -D prisma
pnpm prisma init
위 명령어를 실행하면 prisma/schema.prisma 파일과 .env 파일이 생성됩니다. 이제 .env에 데이터베이스 연결 정보를 입력해야 합니다.
❗
.env파일에는 민감한 정보가 포함되므로 반드시.gitignore에 등록하여 GitHub에 공개되지 않도록 해야 합니다.
기본적으로 .env는 다음과 같이 작성되어 있을 것입니다:
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/portfolio?schema=public"
PostgreSQL을 사용할 것이므로 다음과 같이 수정했습니다:
DATABASE_URL="postgresql://{username}/{password}@localhost:5432/portfolio"
다른 데이터베이스를 사용하시려면 Connection URLs 문서를 참고하시면 됩니다.
이제 prisma/schema.prisma 파일을 수정해야 합니다.
우선 포트폴리오 프로젝트를 위한 기본적인 스키마를 다음과 같이 작성했습니다:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Project {
id String @id @default(cuid())
category String
startDate DateTime
endDate DateTime?
title String
description String
image String
}
더 다양한 타입과 기능들을 활용하시려면 Models 문서를 참고하시기 바랍니다.
스키마 작성이 완료되면 다음 명령어로 실제 데이터베이스에 테이블을 생성할 수 있습니다:
pnpm prisma db push
앞서 언급했듯이 Prisma는 Studio라는 편리한 관리 도구를 제공합니다.
pnpm prisma studio
이 명령어를 실행하면 http://localhost:5555 에서 Studio를 사용할 수 있습니다.
이제 프로젝트에서 prisma를 사용해봅시다.
pnpm add @prisma/client
@prisma/client를 설치했으니 Prisma Client를 초기화하고 사용하는 방법을 설명하겠습니다.
먼저 libs/prisma.ts파일을 생성하여 Prisma Client를 초기화합니다.
import { PrismaClient } from "@prisma/client";
const globalForPrisma = global as unknown as {
prisma: PrismaClient | undefined;
};
const prisma = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
export default prisma;
이제 프로젝트를 조회하는 API를 만들어보겠습니다.
app/api/projects/route.ts:
import prisma from '@/libs/prisma';
import { NextResponse } from 'next/server';
export async function GET() {
try {
const projects = await prisma.project.findMany({
orderBy: { startDate: 'desc' }
})
return NextResponse.json(projects)
} catch {
return NextResponse.json(
{ error: 'Failed to fetch projects' },
{ status: 500 }
)
}
}
프로젝트 정보를 표시하는 컴포넌트에서는 다음과 같이 사용할 수 있습니다:
async function ProjectList() {
const res = await fetch('/api/projects')
const projects = await res.json()
return (
<div>
{projects.map((project) => (
<div key={project.id}>
<h3>{project.title}</h3>
<p>{project.description}</p>
{/* ... */}
</div>
))}
</div>
)
}
프로젝트 추가/수정/삭제 API도 비슷한 방식으로 구현할 수 있습니다. 예를 들어 프로젝트 추가 API:
export async function POST(request: Request) {
try {
const body = await request.json()
const project = await prisma.project.create({
data: body
})
return NextResponse.json(project)
} catch {
return NextResponse.json(
{ error: 'Failed to create project' },
{ status: 500 }
)
}
}