backend
Prisma ORM 완벽 가이드 — Next.js에서 PostgreSQL 연동하는 방법
Prisma ORM을 Next.js 프로젝트에 설정하고, PostgreSQL과 연동해 타입 안전한 데이터베이스 쿼리를 작성하는 방법을 실무 경험 기반으로 정리했다.

- ·Prisma는 schema.prisma 파일 하나로 데이터베이스 스키마, 마이그레이션, 타입을 모두 관리한다
- ·Prisma Client는 schema.prisma를 기반으로 TypeScript 타입을 자동 생성해 쿼리 결과에 타입 안전성을 제공한다
- ·Prisma Migrate는 스키마 변경 이력을 SQL 마이그레이션 파일로 관리해 팀 전체가 동일한 DB 구조를 유지할 수 있다
- ·Next.js App Router에서 Prisma Client는 싱글턴 패턴으로 인스턴스를 생성해야 개발 환경에서 연결이 과도하게 증가하는 문제를 방지할 수 있다
raw SQL이나 pg 모듈로 직접 쿼리를 작성하다가 Prisma로 전환했더니 쿼리 결과에 타입이 자동으로 붙어서 컴파일 타임에 잘못된 필드 접근을 잡을 수 있게 됐다. 마이그레이션도 SQL 파일을 직접 관리하던 방식에서 prisma migrate dev 한 줄로 처리할 수 있게 돼서 팀원 간 DB 스키마 동기화 문제가 크게 줄었다.
Prisma ORM이 기존 방식과 다른 점
Prisma ORM이 PostgreSQL 연동에서 기존 방식보다 나은 이유
기존에 Node.js에서 PostgreSQL을 쓰려면 pg 모듈로 직접 SQL을 작성하거나 Sequelize, TypeORM 같은 ORM을 썼다. raw SQL은 타입 지원이 없어서 쿼리 결과 타입을 직접 선언해야 했고, 오타가 나도 런타임에서야 오류가 발생했다. Prisma는 schema.prisma 파일에 데이터 모델을 정의하면 그 모델을 기반으로 TypeScript 타입이 자동 생성된다. 쿼리를 작성할 때 자동완성이 동작하고, 없는 필드를 참조하면 컴파일 타임에 오류를 잡아준다. 처음 Prisma를 써봤을 때 타입 자동 생성이 가져다주는 개발 편의성이 기대 이상이었다. 쿼리 결과에 타입이 자동으로 붙으니 인터페이스를 별도로 선언할 필요가 없어지고, 리팩터링할 때 필드 이름이 바뀌면 참조하는 코드에 모두 타입 오류가 표시되어 빠뜨리는 부분 없이 수정할 수 있었다. Sequelize나 TypeORM 대비 설정이 간단하고 문서가 잘 정리되어 있어서 초기 진입 장벽도 낮은 편이다.
Next.js에서 Prisma와 PostgreSQL 설정하는 방법
Next.js 프로젝트에 Prisma ORM과 PostgreSQL을 연결하는 방법
Prisma를 Next.js 프로젝트에 추가하려면 npm install prisma @prisma/client로 설치하고 npx prisma init으로 초기화한다. 초기화하면 prisma/schema.prisma 파일과 .env 파일이 생성된다. .env의 DATABASE_URL에 PostgreSQL 연결 문자열을 설정하면 된다. 연결 문자열 형식은 postgresql://사용자:비밀번호@호스트:포트/데이터베이스 형태다. schema.prisma에 데이터 모델을 작성한 뒤 npx prisma migrate dev 명령을 실행하면 마이그레이션 SQL 파일이 생성되고 DB에 적용된다. npx prisma generate를 실행하면 스키마를 기반으로 Prisma Client 타입이 생성된다. migrate dev를 실행하면 generate도 자동으로 실행된다. Next.js App Router에서 Prisma Client를 사용할 때는 개발 환경에서 Hot Reload로 인해 클라이언트 인스턴스가 중복 생성되는 문제를 막기 위해 globalThis에 싱글턴으로 저장하는 패턴을 써야 한다.
// 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'] : [],
});
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma;
}Prisma 스키마로 PostgreSQL 마이그레이션을 관리하는 방법
Prisma Migrate는 schema.prisma의 변경 사항을 SQL 마이그레이션 파일로 자동 생성하고 DB에 적용하는 기능이다. 팀에서 DB 스키마를 변경할 때 SQL 파일을 직접 공유하거나 수동으로 ALTER TABLE을 실행하던 방식에서 벗어날 수 있다. schema.prisma를 수정하고 npx prisma migrate dev --name 변경내용 명령을 실행하면 prisma/migrations 폴더에 타임스탬프가 붙은 SQL 파일이 생성되고 DB에 적용된다. 이 파일은 Git으로 관리하기 때문에 팀원이 코드를 내려받은 뒤 npx prisma migrate deploy 명령 한 줄로 DB를 최신 상태로 맞출 수 있다. 운영 환경에서는 migrate dev 대신 migrate deploy를 쓴다. migrate dev는 shadowing 방식으로 DB를 잠시 리셋했다 복구하는 과정이 있어서 운영 DB에는 쓰면 안 된다. 컬럼 추가, 타입 변경, 인덱스 추가 등 모든 스키마 변경을 이 방식으로 관리하면 누가 언제 어떤 변경을 했는지 이력이 남아서 디버깅에도 유용하다.
Prisma 쿼리 작성 방법
Prisma Client로 PostgreSQL 데이터를 조회하고 생성하는 방법
Prisma Client는 findMany, findUnique, create, update, delete 등의 메서드로 DB를 조작한다. SQL을 직접 쓰는 것보다 코드가 읽기 쉽고, TypeScript 자동완성이 동작해서 실수를 줄일 수 있다. findMany에는 where로 필터, orderBy로 정렬, take와 skip으로 페이지네이션, include로 관계 데이터를 함께 조회하는 옵션을 사용할 수 있다. include를 쓰면 JOIN 쿼리 없이 연관된 테이블 데이터를 함께 가져올 수 있다. 복잡한 쿼리는 prisma.$queryRaw로 raw SQL을 직접 쓸 수도 있다. 이때 Prisma.sql 태그드 템플릿을 쓰면 SQL 인젝션을 방지하면서 동적 값을 바인딩할 수 있다. 트랜잭션이 필요한 경우 prisma.$transaction 안에 여러 쿼리를 묶어서 실행하면 된다. Prisma Studio를 쓰면 웹 GUI에서 DB 데이터를 직접 조회하고 수정할 수 있어서 개발 중 데이터를 확인할 때 편리하다.
자주 묻는 질문
Prisma와 TypeORM 중 어떤 것을 선택해야 하나요?+
TypeScript 타입 안전성과 개발자 경험을 중시한다면 Prisma가 유리하다. TypeORM은 데코레이터 기반이라 기존 클래스 지향 코드와 잘 맞고 다양한 DB를 지원한다. 팀에 ORM 경험이 없다면 Prisma가 진입 장벽이 낮다.
Prisma Migrate를 쓸 때 운영 환경 마이그레이션을 안전하게 하려면 어떻게 해야 하나요?+
운영 환경에서는 migrate dev 대신 migrate deploy를 써야 한다. CI/CD 파이프라인에서 배포 전 npx prisma migrate deploy를 실행하면 미적용 마이그레이션을 자동으로 적용한다. 데이터 손실 위험이 있는 마이그레이션은 배포 전 DB 백업을 먼저 수행해야 한다.
Prisma에서 N+1 문제를 어떻게 해결하나요?+
findMany에 include를 사용하면 연관 데이터를 한 번의 쿼리로 가져오므로 N+1 문제를 피할 수 있다. select로 필요한 필드만 명시하면 불필요한 데이터 조회도 줄일 수 있다. 복잡한 관계 쿼리는 Prisma가 내부적으로 JOIN 또는 IN 쿼리로 최적화한다.
관련 글
PostgreSQL 인덱스와 쿼리 최적화 가이드 — 느린 쿼리를 빠르게 만드는 방법
PostgreSQL에서 데이터가 많아질수록 인덱스 없이는 쿼리가 느려진다. EXPLAIN ANALYZE로 실행 계획을 분석하고, 적절한 인덱스를 추가해 쿼리 속도를 개선하는 방법을 정리했다.
Next.js 환경변수 완벽 가이드 — .env.local부터 NEXT_PUBLIC 클라이언트 변수까지
Next.js에서 API 키는 서버에서만 써야 하므로 NEXT_PUBLIC 없이, 브라우저에서도 써야 하면 NEXT_PUBLIC를 붙여야 한다. .env 파일 종류, 서버/클라이언트 변수 구분, 환경별 설정까지 정리했다.
TypeScript strict 모드 설정 완벽 가이드 — tsconfig 옵션과 자주 만나는 타입 오류 해결
TypeScript strict 모드를 켜면 런타임 버그를 컴파일 타임에 잡을 수 있다. strictNullChecks, noImplicitAny 등 핵심 옵션의 동작 방식과 활성화 시 자주 나타나는 오류 해결법을 정리했다.