빌드 시간 70% 단축! Next.js에 Yarn Berry(PnP) 끼얹기 (feat. Docker 삽질기)

임홍원·2026년 2월 3일

오늘은 최근 회사 프로젝트에서 Next.js 프로젝트의 빌드 타임을 획기적으로 줄이기 위해 Yarn Classic(v1)에서 Yarn Berry(v4, PnP)로 마이그레이션 한 경험을 공유하려고 합니다.

결론부터 말씀드리면, 78초 걸리던 빌드가 25초로 줄어들었습니다. (약 3배 빨라졌네요 🚀)

물론 그 과정이 순탄치만은 않았습니다. 특히 Docker 환경과 k8s 배포 과정에서 마주친 Cannot find module 에러들과의 사투... 그 해결 과정을 정리해 봅니다.

1. 배경: 우리 빌드는 왜 이렇게 느릴까?

저희 서비스 환경은 대략 이렇습니다.

  • Framework: Next.js 14.2.35
  • Infra: Docker, Kubernetes (k8s)
  • Package Manager: Yarn Classic (v1) -> Yarn Berry (v4) 도입 예정

기존 Yarn v1은 빌드할 때마다 그 무거운 node_modules를 생성하고, I/O 작업을 수행하느라 시간을 많이 잡아먹었습니다. 로컬이랑 CI 서버랑 설치 속도 차이도 컸고요.

그래서 결심했습니다. "Zero-Install까지는 아니더라도, PnP(Plug'n'Play)를 도입해서 node_modules를 없애버리자!"

2. 마이그레이션 시작 & VSCode의 반란

호기롭게 Yarn 버전을 올렸습니다.

yarn set version berry
yarn install

터미널에서 설치가 순식간에 끝났습니다. "와, 진짜 빠르네?" 하고 VSCode를 켠 순간...

코드 전체가 빨간 줄로 도배되었습니다.

"Cannot find module 'react'..." "Cannot find module 'next'..."

Yarn PnP는 실제 node_modules 폴더가 없기 때문에, VSCode가 타입을 찾지 못해서 생기는 문제였습니다. 다행히 이건 공식 문서에 해결책이 바로 있더군요.

✅ 해결: Editor SDK 설치

yarn dlx @yarnpkg/sdks vscode

이 명령어 한 방이면 .vscode/settings.json 이 자동으로 수정되면서, VSCode가 PnP 압축 파일(Zip) 내부의 타입을 투시(?)해서 읽을 수 있게 됩니다. 평화가 찾아왔습니다.

3. 난관: Docker 런타임 에러 (The 'Cannot find module' Nightmare)

로컬 개발 환경 세팅을 마치고, 신나게 Docker 이미지를 말아서 배포 테스트를 했습니다. 빌드(Build Stage)는 잘 넘어갔습니다. 그런데 컨테이너를 실행(Run)하자마자 죽어버립니다.

Error: Cannot find module 'next'
Require stack:
- /app/server.js
...

분명히 .pnp.cjs 파일도 복사했고, 하라는 대로 다 했는데 왜 모듈을 못 찾을까요?

🕵️‍♂️ 원인 분석: 캐시가 어디 갔지?

알고 보니 캐시 경로가 문제였습니다. Yarn Berry는 기본적으로 전역 캐시(Global Cache)를 사용하려 하는데, Docker 멀티 스테이지 빌드 과정에서 이 캐시가 제대로 전달되지 않거나 엉뚱한 곳에 저장되고 있었던 겁니다.

컨테이너 내부에서 확실하게 의존성을 잡으려면, 캐시 폴더를 프로젝트 내부로 고정해주는 것이 정신건강에 좋다는 걸 깨달았습니다.

✅ 해결: .yarnrc.yml 설정 추가

.yarnrc.yml 파일에 캐시 관련 설정을 명시적으로 추가했습니다.

# .yarnrc.yml

nodeLinker: pnp
enableGlobalCache: false      # 글로벌 캐시 끄기 (프로젝트 내부에 저장)
cacheFolder: ./.yarn/cache    # 캐시 경로를 프로젝트 루트 아래로 고정

yarnPath: .yarn/releases/yarn-4.12.0.cjs

이렇게 하면 yarn install 시 생성되는 의존성 파일들이 .yarn/cache 폴더에 예쁘게 모입니다. 덕분에 Dockerfile에서 .yarn 폴더만 복사하면 누락되는 파일 없이 완벽하게 실행 환경이 구성됩니다.

4. 최종 보스: Next.js Standalone + PnP Dockerfile

Next.js의 output: 'standalone' 은 이미지 용량을 줄이기 위해 필수지만, 기본적으로 node_modules 구조를 가정하고 만들어집니다. PnP와는 물과 기름 같은 사이죠.

그래서 Standalone 빌드 결과물에 PnP 환경을 강제로 주입(Injection) 하는 전략으로 최종 Dockerfile을 완성했습니다.

기본적인 Dockerfile은 작성되었다고 가정합니다.
여기서는 필수적인 부분만 작성되었습니다

🛠️ 완성된 Dockerfile

# ---- Stage 1: Buildtime ----

# Corepack 활성화 (Yarn berry를 사용하기 위해 필수)
RUN corepack enable

# PnP 환경 복사 (중요: .yarnrc.yml 포함)
COPY package.json yarn.lock ./
COPY .yarnrc.yml ./
COPY .pnp.cjs ./
COPY .pnp.loader.mjs ./
COPY .yarn ./.yarn

# 의존성 설치
RUN yarn install --immutable

# ---- Stage 2: Runtime ----

# Standalone 결과물 복사
# (주의: Standalone은 node_modules 기반이라 PnP에선 껍데기일 수 있음)
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./

# ★ 핵심: PnP 런타임 덮어쓰기 ★
# Standalone이 만든 불완전한 .yarn을 지우고, 빌드 스테이지의 완벽한 .yarn을 복사
RUN rm -rf ./.yarn
COPY --from=builder /app/.pnp.cjs ./
COPY --from=builder /app/.pnp.loader.mjs ./
COPY --from=builder /app/.yarn ./.yarn/

# ★ 핵심: Node 실행 시 PnP 로더 강제 주입
ENV NODE_OPTIONS="--require=/app/.pnp.cjs --loader=/app/.pnp.loader.mjs"

# 잘 로드되는지 확인 사살
RUN node -e "require('next/package.json'); console.log('next ok')"

# 실행
CMD ["node", "server.js"]

이 설정의 핵심은 NODE_OPTIONS입니다. node server.js 가 실행될 때 --require--loader 옵션을 통해 PnP 시스템을 먼저 로드하게 만들어서, node_modules 없이도 압축된 패키지들을 찰떡같이 찾아내게 만들었습니다.

5. 결과: 압도적인 성능 차이

자, 이제 고생한 보람을 느낄 차례입니다.

Before (Yarn Classic v1) node_modules 압축 풀고... 유효성 검사하고... I/O 병목 생기고...
총 소요 시간: 78.0초

After (Yarn Berry v4 PnP) 의존성 설치가 순식간에 끝나고 빌드도 쾌적합니다.
총 소요 시간: 25.2초

78초 ➡️ 25초
단순 계산으로도 3배 이상 빨라졌습니다

마치며

Next.js의 Standalone 모드와 Yarn PnP는 구조적으로 서로 지향하는 바가 달라서(물리 파일 vs 가상 파일 시스템), 초기 세팅에 애를 좀 먹었습니다.

하지만 .yarnrc.yml 에서 cacheFolder 를 확실히 잡아주고, Dockerfile에서 NODE_OPTIONS를 통해 PnP 로더를 주입해 주니 아주 안정적으로 돌아가네요. 배포 속도가 빨라지니 개발 생산성도 오르고, CI 돌아가는 거 멍하니 바라보는 시간도 줄어서 아주 만족스럽습니다.

혹시 저처럼 Next.js + Docker + Yarn Berry 조합에서 Cannot find module 에러로 고통받고 계신 분들에게 이 글이 도움이 되었으면 좋겠습니다!

profile
Frontend Developer

2개의 댓글

comment-user-thumbnail
2026년 2월 3일

멋지십니다.

1개의 답글