npm, yarn, pnpm, corepack: 패키지 매니저 전환 히스토리와 선택 기준

npm, yarn, pnpm, corepack: 패키지 매니저 전환 히스토리와 선택 기준
Node.js 생태계에서 패키지 매니저는 단순히 install 명령을 수행하는 도구가 아니다.
특히 팀 개발에서는 "의존성을 어떻게 설치하느냐"보다 "같은 결과를 얼마나 안정적으로 재현하느냐"가 더 중요해진다.
나는 npm -> yarn -> pnpm -> corepack 순서로 도구를 옮겨 왔고,
이번 글에서는 각 전환의 이유를 기술적 관점에서 짧게 정리해 보려고 한다.
목차
패키지 매니저 선택이 중요한 이유
패키지 매니저 선택은 개인 취향 문제처럼 보이지만, 팀 단위로 가면 아래 비용으로 바로 연결된다.
- 로컬/CI 불일치 비용: 내 로컬에서는 되는데 CI에서 실패하는 비용.
- 온보딩 비용: 새 팀원이 환경을 맞추는 데 드는 시간.
- 릴리즈 안정성 비용: 의존성 해석이 달라져서 배포 직전에 깨지는 비용.
즉, 핵심은 "가장 빠른 도구"보다 "팀에서 반복 가능한 설치 결과를 만드는 도구 + 규칙"에 가깝다.
패키지 매니저 전환 히스토리
1) npm을 쓰던 시기
처음에는 기본 제공 도구인 npm으로 충분했다. npm은 Node.js 기본 패키지 매니저라는 점에서 "가장 넓은 호환성"이라는 장점이 있다.
특히, 문서와 예제가 많고, 대부분의 튜토리얼이 npm 기준이라 학습 장벽이 낮았기 때문이다.
다만 프로젝트가 커지거나 팀 단위 협업이 늘어나면, 도구 자체보다 버전/환경 통제가 더 중요한 이슈로 올라오기 시작했다.
2) yarn으로 이동
yarn은 Meta에서 만든 패키지 매니저로, npm의 성능과 안정성 문제를 보완하기 위해 등장했다.
2016년경에 처음 나왔을 때, npm보다 빠른 설치 속도와 더 나은 의존성 관리 경험 때문에 많은 팀이 yarn으로 전환했다.
특히 yarn.lock 파일을 통해 의존성 트리를 명확하게 관리할 수 있다는 점이 큰 장점으로 작용했다.
당시에는 "npm보다 yarn이 더 낫다"는 분위기가 강했고, 설치 체감 속도와 사용 경험 때문에 자연스럽게 yarn을 사용하게 되었다.
하지만 시간이 지나면서 "어떤 패키지 매니저를 쓰는가"보다 "어떤 버전을 팀이 강제로 동일하게 쓰는가"가 더 중요하다는 점을 느꼈다.
3) pnpm으로 이동
pnpm은 yarn과 비슷한 시기에 등장했지만, 의존성 저장 방식에서 근본적으로 다른 접근을 취했다. pnpm은 패키지를 중복 저장하는 대신, 공유 저장소와 링크를 활용하여 디스크 효율과 설치 속도를 개선하는 구조로 설계되었다.
팀에서 pnpm을 사용하면서 본격적으로 전환했다. 전환 이유는 단순했다.
- 설치 성능 체감이 좋았고,
- workspace 기반 운영이 편했으며,
- lockfile 중심 재현성 관리가 수월했다.
특히, 구조적으로는 패키지를 중복 저장하기보다 공유 저장소와 링크를 활용하는 방식이라, 프로젝트 규모가 커질수록 디스크 효율과 설치 속도 측면의 장점이 더 잘 드러났다.
여기서 중요한 점은 "pnpm이 무조건 더 좋다"가 아니라, 팀 규칙(훅, CI, lockfile 정책)과 함께 쓸 때 효과가 커진다는 점이다.
4) corepack을 붙인 현재
corepack은 Node.js 16.9부터 실험적으로 도입된 도구로, 패키지 매니저 버전을 프로젝트 단위로 고정할 수 있게 해준다.
corepack을 사용하면 package.json의 packageManager 필드에 원하는 패키지 매니저와 버전을 명시할 수 있다.
최근에는 corepack을 통해 패키지 매니저 버전까지 고정하는 흐름을 실험 중이다.
package.json의 packageManager 필드에 버전을 명시하여, 로컬과 CI에서 동일한 버전의 도구를 강제하기가 쉬워졌다.
파이썬의 venv처럼 "실행 환경을 맞춘다"는 감각과 비슷하다.
npm/yarn/pnpm 버전을 프로젝트 단위로 일치시키는 레이어라는 점에서 "도구 선택"보다 "도구 버전 통제"에 더 가까운 역할을 한다.
이렇게 하면 "도구는 뭐든지"라는 유연성을 유지하면서도,"도구 버전이 달라서 발생하는 불일치" 문제를 효과적으로 줄일 수 있다.
비교 기준 3가지: 속도, 재현성, 호환성
이 섹션의 평가는 정량 벤치마크가 아니라 일반 경향 + 내 체감 기준이라는 점을 먼저 밝힌다.
1) 설치/빌드 속도
- 체감상:
pnpm으로 옮긴 뒤 설치 속도와 디스크 효율이 개선되었다. - 해석: 의존성 저장 방식과 캐시 구조 차이 때문에, 프로젝트 규모가 커질수록 차이가 체감되기 쉽다.
- 주의: 팀마다 네트워크, CI 캐시, 레지스트리 미러 설정이 달라 절대 성능은 동일하지 않다.
2) 재현성/lockfile 신뢰도
실무에서는 이 항목이 가장 중요했다.
- 로컬에서 설치되는 의존성과 CI 설치 결과가 일치하는가?
- 팀원 A/B의 패키지 매니저 버전 차이가 결과에 영향을 주는가?
--frozen-lockfile같은 정책을 CI에서 강제하는가?
lockfile 이름은 도구마다 다르지만, 목적은 동일하다. "같은 dependency tree를 재현"하는 것이다.
| Manager | Lockfile |
|---|---|
| npm | package-lock.json |
| yarn | yarn.lock |
| pnpm | pnpm-lock.yaml |
도구 선택보다 먼저, "lockfile을 기준으로 실패를 빠르게 감지하는 파이프라인"을 갖추는 편이 효과가 컸다.
3) 생태계 호환성
npm은 기본값으로서 호환성이 넓고, yarn/pnpm은 프로젝트 성격에 따라 이점이 크다.
다만 실제 운영에서는 패키지 매니저 자체보다 다음 요소가 호환성 이슈를 더 크게 만든다.
- 오래된 의존성,
- 전역 도구 버전 불일치,
- lockfile 미커밋,
- 설치 명령 혼용(
npm install과pnpm install혼용).
참고로 체감 비교를 아주 짧게 요약하면, 최근 흐름에서는 다음 경향이 자주 관찰된다.
| 항목 | npm | yarn | pnpm |
|---|---|---|---|
| 설치 속도 | 보통 | 빠름 | 빠름~매우 빠름 |
| 디스크 효율 | 낮음~보통 | 보통 | 높음 |
| strict dependency | 제한적 | 설정에 따라 다름 | 상대적으로 강함 |
| monorepo/workspace 운영 | 가능 | 강점 있음 | 강점 있음 |
이 표는 어디까지나 일반 경향이다. 실제 결과는 레지스트리, 캐시, CI 러너, 저장소 구조에 따라 달라진다.
lockfile 불일치 경험
실제로 팀원이 yarn으로 의존성을 추가한 뒤 코드만 커밋하고 lockfile 변경을 누락했던 경험이 있었다.
로컬은 캐시 덕분에 통과하지만 CI는 깨끗한 환경에서 yarn install --frozen-lockfile가 즉시 실패하면서 배포 파이프라인이 멈췄다.
이러한 경험이 반복되다 lockfile은 부수 파일이 아니라 재현성의 핵심 산출물이라는 점이 분명해졌고, 결국 훅과 CI에서 lockfile 검증과 패키지 매니저 버전 고정을 함께 강제해야 한다는 결론에 도달하게 됐다.
선택 기준에 대하여
정답은 "무조건 pnpm"도, "무조건 npm"도 아니다. 팀의 운영 방식에 맞는지 확인하는 것이 먼저다.
아래 세 가지 질문으로 판단할 때, 의사 결정에 도움이 되었다.
질문 1: 재현성이 지금 병목인가?
로컬과 CI 결과가 자주 어긋난다면, 도구 선호보다 먼저 lockfile 강제 정책과 매니저 버전 고정부터 적용하는 편이 효과적이다.
질문 2: 저장소 규모가 현재 방식을 압박하는가?
workspace가 커지고 의존성 수가 늘어날수록,
설치 시간과 디스크 효율은 체감되는 운영 비용이 된다.
이때는 pnpm의 구조적 장점이 실무 이점으로 연결될 가능성이 높다.
질문 3: 팀 규칙을 실제로 강제할 수 있는가?
어떤 도구를 택하든 팀 문서, 훅, CI가 같은 방향을 바라봐야 한다.
공식 설치 명령을 하나로 고정하고,
packageManager와 lockfile 검증을 자동화할 수 있어야 전환 효과가 유지된다.
마무리하며
내 현재 선택은 "도구 하나"가 아니라, 아래 3가지를 함께 가져가는 운영 방식이다.
pnpm으로 설치/워크스페이스 운영,corepack으로 패키지 매니저 버전 고정,- 훅 + CI로 lockfile 재현성 강제.
패키지 매니저 논쟁의 결론은 선호가 아니라 재현성이다. 팀이 같은 입력으로 같은 결과를 얻는 구조를 먼저 만들면, 그 다음의 도구 선택은 훨씬 단순해진다.