← 전체 글로 돌아가기

서버 운영

배포 서버에서 prisma generate를 다시 돌려야 하는 이유

Prisma Client는 플랫폼별 바이너리를 포함한다. 로컬에서 생성한 클라이언트를 그대로 Linux 서버에 올리면 조용히 실패한다.

Prisma를 쓰다 보면 로컬에서는 잘 돌아가던 앱이 배포 서버에서 엉뚱한 에러를 내는 경우가 있다. PrismaClientInitializationErrorQuery engine binary not found 같은 메시지가 그것이다. 원인은 간단한데, Prisma Client가 플랫폼에 종속된 바이너리를 함께 생성하기 때문이다.

왜 플랫폼 바이너리가 문제인가

prisma generate를 실행하면 .prisma/client 아래에 자바스크립트 래퍼뿐만 아니라 Rust로 작성된 쿼리 엔진 바이너리가 함께 만들어진다. 이 바이너리는 현재 실행 중인 OS와 아키텍처에 맞게 선택된다. macOS Apple Silicon에서 생성하면 libquery_engine-darwin-arm64.dylib.node가, Ubuntu 22.04에서 생성하면 libquery_engine-debian-openssl-3.0.x.so.node가 필요하다.

CI/CD 파이프라인에서 npm ci만 하고 prisma generate를 생략하거나, 로컬에서 빌드한 결과물을 그대로 서버에 복사하면 바이너리 플랫폼 불일치가 발생한다.

schema.prisma에 binaryTargets 추가하기

가장 근본적인 해결책은 schema.prisma에 배포 대상 플랫폼을 명시하는 것이다.

generator client {
  provider      = "prisma-client-js"
  binaryTargets = ["native", "debian-openssl-3.0.x"]
}

native는 현재 실행 환경을 자동 감지한다. 배포 서버가 Ubuntu 22.04라면 debian-openssl-3.0.x, 20.04라면 debian-openssl-1.1.x를 추가한다. Alpine Linux 기반 Docker 이미지를 쓴다면 linux-musl을 넣어야 한다.

정확한 대상값은 배포 서버에서 아래 명령으로 확인한다.

openssl version
uname -m

배포 파이프라인에서 generate 위치

Dockerfile이나 CI 스크립트에서 npm ci 다음에 prisma generate를 반드시 포함시켜야 한다.

RUN npm ci
RUN npx prisma generate
RUN npm run build

순서가 중요하다. prisma generate@prisma/client 패키지가 설치된 이후에 실행해야 하고, 앱 빌드 전에 끝나야 한다. generate를 빌드 후에 돌리면 빌드 과정에서 Prisma Client를 import하는 타입 오류가 발생할 수 있다.

마이그레이션은 별도

prisma generate는 클라이언트 코드 생성만 한다. DB 스키마 변경은 prisma migrate deploy로 따로 처리한다. 컨테이너 시작 스크립트에서 migrate와 generate를 묶어 돌리는 경우도 있는데, 이렇게 하면 DB 연결이 없는 빌드 단계에서 문제가 생길 수 있으니 역할을 명확히 분리해두는 게 좋다.