개발에 AtoZ까지

[JS] corepack enable 한 줄이 곧 안 먹습니다 — npm·pnpm·yarn 2026년 정리 본문

프론트엔드/JAVASCRIPT

[JS] corepack enable 한 줄이 곧 안 먹습니다 — npm·pnpm·yarn 2026년 정리

AtoZ 개발자 2026. 8. 30. 21:10
반응형

CI 설정이나 Dockerfile에 이런 줄을 넣어 두신 분들이 많을 겁니다.

RUN corepack enable
RUN pnpm install --frozen-lockfile

Node 25부터 Corepack이 Node.js에 안 들어갑니다. Node 26에는 corepack 실행 파일이 없고 API 문서 페이지도 사라졌습니다. 그러니까 새 LTS로 올라가는 순간 이 줄이 command not found로 깨지거나 조용히 실패합니다.

Node 26은 2026년 10월 28일에 LTS가 됩니다. 두 달 남았습니다.

이 글을 다 읽으면 세 가지가 정리됩니다. 첫째, Corepack에 의존하던 파이프라인을 어떻게 고칠지 알 수 있습니다(공식 대체안이 매니저별로 다릅니다). 둘째, 세 매니저 중 우리 프로젝트에 맞는 걸 고를 기준이 생깁니다. 셋째, 락파일과 CI 명령을 팀 표준으로 못박을 수 있습니다.

이 글은 Node.js·npm·pnpm·Yarn 공식 문서와 npm 레지스트리 메타데이터를 확인해 정리했습니다(확인일 2026-08-23). 버전 숫자는 주 단위로 바뀌니 확인일 기준으로 읽어 주세요.

Corepack이 번들된 마지막 LTS와 새 LTS의 경계

Corepack이 죽은 건 아닙니다

먼저 오해 하나를 정리하겠습니다. "Node에서 빠졌으니 Corepack은 끝난 프로젝트"라는 얘기가 도는데, 아닙니다.

번들 배포만 중단됐고 프로젝트는 살아 있습니다. npm의 corepack 패키지는 0.35.0이 2026년 5월 15일에 배포됐고 deprecated 표시가 없습니다. 저장소도 아카이브되지 않았습니다.

Corepack README의 문장이 이렇습니다.

"Corepack is distributed with Node.js from version 14.19.0 up to (but not including) 25.0.0. Run corepack enable to install the required Yarn and pnpm binaries on your path."

Node 24 문서에도 공지가 남아 있습니다.

"Corepack will no longer be distributed starting with Node.js v25. Users currently depending on the bundled corepack executable from Node.js can switch to using the userland-provided corepack module."

즉 "userland 패키지로 옮겨 쓰라"는 안내입니다. 그런데 매니저별 공식 권고가 갈립니다.

대체안이 매니저마다 다릅니다

Yarn — 공식 설치 문서가 이제 첫 단계로 Corepack 설치를 지시합니다.

npm install -g corepack
yarn init -2

pnpm — 공식 CI 문서가 Corepack을 걷어냈습니다. 이유가 폐기 때문이 아니라 성능입니다. Corepack이 pnpm 자리에 JS shim을 깔아서 호출마다 Node.js를 먼저 띄우기 때문입니다. 대체안은 자체 설치 스크립트입니다.

curl -fsSL https://get.pnpm.io/install.sh | sh -

npm — Node에 번들되어 오니 별도 설치가 필요 없습니다. 다만 아래 버전 문제가 있습니다.

번들 npm은 최신 npm이 아닙니다

이것도 자주 걸리는 부분입니다.

  버전
npm 최신 안정 12.0.2 (2026-07-29)
Node 26.7.0에 들어 있는 npm 11.19.0
Node 24.19.0(LTS)에 들어 있는 npm 11.17.0

npm 메이저 기능을 쓰려면 번들 버전을 확인하고 따로 올려야 합니다.

그리고 npm 12는 아무 Node에나 올라가지 않습니다. engines 값이 이렇습니다.

"engines": { "node": "^22.22.2 || ^24.15.0 || >=26.0.0" }

caret 범위라는 점을 정확히 읽어야 합니다. ^22.22.2는 22.22.2 이상 23 미만이고, ^24.15.0은 24.15.0 이상 25 미만입니다. 그러니까 Node 23과 Node 25는 전 구간 미지원입니다. "24.15.0 이상"으로만 옮기면 틀립니다.

락파일과 CI 명령을 못박기

팀 표준으로 문서에 한 줄씩 적어 두면 사고가 줄어드는 항목입니다.

매니저 락파일 CI 설치 명령
npm package-lock.json npm ci
pnpm pnpm-lock.yaml pnpm install --frozen-lockfile
Yarn yarn.lock yarn install --immutable

세 매니저 모두 공식 문서가 락파일 커밋을 요구합니다.

여기서 알아 두면 편한 게 있습니다. pnpm과 Yarn은 CI를 감지하면 기본으로 그 모드입니다.

pnpm 문서는 --frozen-lockfile 기본값이 비CI에서는 false, CI에서는 (락파일이 있으면) true라고 명시합니다. Yarn 문서도 --immutable (defaults to true on CI)라고 괄호로 적어 둡니다.

명시적 플래그가 사실상 필수인 쪽은 npm입니다. 그리고 npm은 플래그가 아니라 npm ci라는 별도 명령을 씁니다.

CI에서 npm install을 쓰면 안 되는 이유가 여기 있습니다. npm ci는 락파일이 package.json과 어긋나면 락파일을 갱신하는 대신 에러로 종료하고 node_modules를 먼저 지웁니다. 반면 npm install은 락파일을 조용히 고쳐 씁니다. CI에서 조용히 고쳐 쓰는 건 재현성을 깨는 일입니다.

pnpm 쪽에도 비슷한 함정이 있습니다. CI의 pnpm 버전을 락파일 생성 버전보다 낮게 두면 안 됩니다. pnpm v11부터는 더 높은 메이저가 쓴 락파일을 CI에서 만나면 조용히 재작성하지 않고 에러를 냅니다.

pnpm 공식 CI 문서의 설치 안내 (확인일 2026-08-23)

pnpm이 해결하는 문제

pnpm의 설계 목표가 문서에 명시돼 있습니다. content-addressable store + 하드링크입니다.

npm이나 Yarn Classic은 프로젝트마다 node_modules에 패키지 사본을 만듭니다. 같은 라이브러리를 쓰는 프로젝트가 100개면 사본이 100개죠. pnpm은 전역 스토어 한 곳에 저장하고 하드링크로 연결합니다.

그래서 디스크와 설치 시간이 실제 병목이거나 모노레포라면 실익이 큽니다. 다만 루트에 pnpm-workspace.yaml을 반드시 둬야 합니다.

pnpm 12는 아직 기다리는 게 좋습니다. Rust 재작성판인데, 공식 문서가 'currently a release candidate'로 명시합니다. 현재 12.0.0-rc.8이고 npm의 next-12 태그로만 배포됩니다. Homebrew·winget·Scoop·Chocolatey도 아직 제공하지 않습니다.

프로덕션 표준은 11.22.0으로 두는 편이 안전합니다.

Yarn PnP가 잡아 주는 것

Yarn Berry의 PnP(Plug'n'Play)는 node_modules 자체를 만들지 않습니다. 그 결과 유령 의존성을 강하게 막아 줍니다. package.json에 선언하지 않은 패키지가 다른 패키지의 의존성으로 우연히 설치되어 import되는 문제죠.

다만 마찰이 있습니다. 문서 스스로 인정하듯이, 다른 매니저에서는 그냥 돌던 것이 에러로 보고됩니다. 해결 수단은 .yarnrc.ymlpackageExtensions입니다.

PnP는 강제가 아닙니다. "Berry를 쓰면 PnP를 받아들여야 한다"고 알려져 있는데, 문서가 되돌리는 방법을 명시합니다.

# .yarnrc.yml
nodeLinker: node-modules   # pnp | pnpm | node-modules 세 값

Yarn Classic으로 설치돼 있던 프로젝트에서 yarn install을 돌리면 PnP가 자동으로 비활성화되기까지 합니다.

설치 방법에 함정이 하나 있습니다.

npm install -g yarn   # ← 이건 Yarn Classic 1.22.22 입니다

npm의 yarn 패키지는 아직 1.22.22(Classic)입니다. Yarn 공식 Q&A가 '모던 Yarn은 2019년 이후 npm에 배포되지 않는다'고 직접 밝히고 있고, npm의 berry 태그도 2.4.3에 멈춰 있습니다.

현재 Yarn stable은 4.18.0이고, Corepack이나 yarn set version으로 받습니다. 그리고 Yarn Classic 1.x는 2020년 1월에 이미 유지보수 모드에 들어갔습니다. 새 프로젝트의 표준으로 채택하지 않는 게 좋습니다.

세 매니저의 node_modules 구조 차이와 되돌리는 설정

심링크를 못 쓰는 환경

pnpm의 기본 링커는 isolated이고 심링크를 씁니다. 그래서 심링크를 지원하지 않는 배포 방식에서 문제가 생깁니다.

pnpm 자신이 탈출구를 문서화해 뒀습니다.

# pnpm-workspace.yaml (또는 .npmrc)
nodeLinker: hoisted   # npm·Yarn Classic 과 같은 평평한 node_modules

문서가 정당한 사유로 든 예시가 두 개입니다. React Native 프로젝트심링크 미지원 서버리스(AWS Lambda에 소스를 그대로 올리는 방식)입니다.

React Native·Expo는 특히 조심하셔야 합니다. Yarn 공식 문서가 danger 박스로 'React Native / Expo는 일반 node_modules 설치가 필요하다'고 예외 처리해 뒀습니다. 즉 PnP를 붙이면 안 됩니다. pnpm도 같은 이유로 nodeLinkerhoisted로 바꿔야 한다고 문서가 말합니다.

React Native 프로젝트를 하고 계시다면 Expo와 React Native CLI 중 어떤 방식으로 시작할까에서 프로젝트 구성 자체를 다뤘으니 함께 보시면 좋습니다.

packageManager 필드는 표준인가요

지형이 갈려 있습니다.

매니저 입장
Yarn·Corepack packageManager를 정식 필드로 문서화 (name@x.y.z 필수, SHA-224 해시 권장, 허용값 yarn/npm/pnpm)
pnpm 이를 'the legacy packageManager field'로 부르고, 버전 범위를 지원하는 devEngines.packageManager(pnpm v11.0.0 도입)를 권장
npm 공식 package.json 문서에 최상위 packageManager 항목이 없고 devEngines만 있음

그래서 devEngines.packageManager로 옮기는 작업은 서두르지 않는 게 좋습니다. 팀이 쓰는 매니저 하나가 실제로 무엇을 검증하는지 확인한 뒤 옮기시면 됩니다.

그래서 뭘 고르나요

지영 씨 팀 상황으로 정리하겠습니다. Node 24 LTS, npm 사용, GitHub Actions에서 corepack enable 없이 npm ci만 쓰고 있고, 모노레포는 아닙니다.

이 팀은 당장 급한 게 없습니다. Node 24 지원 종료가 2028년 4월 30일이고 그때까지 번들 corepack이 남아 있습니다. 다만 Node 26 LTS로 올릴 계획을 세울 때 Corepack 의존이 없는지 확인해 두면 됩니다.

일반화하면 이렇습니다.

지금 해야 할 것

  • Node 26 이상으로 올릴 예정이면 CI·Dockerfile에서 corepack enable 의존을 걷어낸다
  • 대체안을 매니저에 맞게 고른다 — Yarn은 npm install -g corepack, pnpm은 자체 설치 스크립트
  • 락파일과 CI 설치 명령을 팀 문서에 한 줄로 못박는다
  • CI에서 npm install 대신 npm ci를 쓰는지 확인한다
  • CI의 pnpm 버전이 락파일 생성 버전보다 낮지 않은지 확인한다
  • npm 12 기능이 필요하면 번들 버전을 확인하고 따로 올린다

pnpm으로 갈 만한 경우

  • 디스크·설치 시간이 실제 병목이다
  • 모노레포다 (루트에 pnpm-workspace.yaml 필수)

Yarn PnP를 볼 만한 경우

  • 유령 의존성을 지금 잡아야 한다
  • packageExtensions로 마찰을 해결할 여력이 있다

기다릴 것

  • pnpm 12 — release candidate입니다. 표준은 11.22.0으로
  • devEngines.packageManager로 이전 — 매니저별 검증 동작을 먼저 확인

하지 말 것

  • React Native·Expo 프로젝트에 Yarn PnP 붙이기 (문서가 예외 처리)
  • 심링크 미지원 배포 대상에 pnpm 기본 isolated 링커 결과물 올리기
  • npm install -g yarn으로 Berry 설치하려 하기 (Classic 1.22.22가 깔립니다)
  • Yarn Classic 1.x를 새 프로젝트 표준으로 채택하기
  • CI에서 npm install 쓰기

확인 목록

[ ] CI·Dockerfile 에서 corepack enable 사용처를 찾았다
[ ] 올릴 Node 버전이 25 이상인지 확인했다 (25+ 는 corepack 없음)
[ ] 매니저별 공식 대체안을 적용했다
[ ] 락파일이 저장소에 커밋되어 있다
[ ] CI 설치 명령이 npm ci / --frozen-lockfile / --immutable 인가
[ ] npm 12 를 쓴다면 Node 버전이 engines 범위에 들어가는가 (23·25 미지원)
[ ] React Native·Expo 프로젝트에 PnP 나 isolated 링커를 안 쓰고 있는가
[ ] 배포 대상이 심링크를 지원하는가

찾을 대상을 훑는 명령입니다.

# Corepack 의존 사용처
grep -rn "corepack" . --include=Dockerfile --include=*.yml --include=*.yaml --include=*.sh --include=package.json

# CI 에서 npm install 을 쓰고 있는지
grep -rn "npm install" .github/ 2>/dev/null

# 현재 버전 확인
node -v && npm -v
npm view npm version
npm view pnpm version
npm view yarn version   # Classic 1.x 가 나오는 걸 직접 확인해 보세요

다음에 볼 글

프런트엔드 쪽 자바스크립트 문법을 정리하고 계신다면 Promise.all·allSettled·any·race 구분Javascript 동기/비동기 처리가 짝이 되는 글입니다. 모듈 import 방식이 헷갈린다면 JS Import 하는 방법과 차이점을 먼저 보시면 좋습니다. 빌드 도구 쪽에서 비슷한 결정을 하고 계신다면 내일 올릴 Gradle DSL 전환 글도 같은 성격입니다.

버전 숫자는 주 단위로 바뀝니다. 이 글의 버전은 모두 2026년 8월 23일 확인 기준이고, 논지의 중심은 버전 숫자가 아니라 Corepack 번들 중단이라는 구조 변화입니다. 실제 작업 전에 각 매니저의 공식 문서로 최신 값을 확인해 주세요. 잘못된 내용이나 보충이 필요한 부분이 있으면 댓글로 알려 주시면 반영하겠습니다.

참고한 자료

  • nodejs/corepack — README와 배포 중단 안내 (확인일 2026-08-23)
  • Node.js v24 / v26 Documentation — Corepack 페이지 상태 (확인일 2026-08-23)
  • npm 레지스트리 — npm·pnpm·yarn·corepack 매니페스트와 dist-tag (확인일 2026-08-23)
  • npm Docs — npm cinpm install의 차이 (확인일 2026-08-23)
  • pnpm 공식 문서 — Continuous Integration, pnpm install CLI, node-modules 설정, package.json (확인일 2026-08-23)
  • Yarn 공식 문서 — Getting Started(설치), Q&A, Plug'n'Play, nodeLinker (확인일 2026-08-23)
  • nodejs.org/dist/index.json — Node 버전별 번들 npm 버전 (확인일 2026-08-23)
반응형
Comments