
2026년 현재 JavaScript 의존성을 관리할 수 있는 제대로 된 선택지는 네 가지이며, 이들 사이의 격차는 그 어느 때보다 벌어져 있습니다. npm 11은 공급망 보안을 강화하기 위해 min-release-age와 npm trust를 도입했습니다. pnpm 10은 라이프사이클 스크립트를 기본적으로 옵트인(opt-in) 방식으로 바꿨습니다. Yarn 4는 Plug'n'Play 엔진과 JS 기반 constraints를 한층 성숙하게 다듬었습니다. Bun 1.3은 의존성 카탈로그, bun why, 대화형 업데이트를 추가했습니다. 2026년 최고의 node 패키지 매니저를 고르는 일은 더 이상 "npm은 느리니까 다른 걸 써봐"의 문제가 아닙니다. 프로젝트에 맞는 올바른 아키텍처를 선택하는 문제입니다.
이 JavaScript 패키지 매니저 비교 글은 다른 가이드가 건너뛰는 내용을 담고 있습니다. 구체적인 하드웨어에서 측정한 실제 설치 속도 벤치마크, 모든 워크플로를 다루는 나란한 코드 예제, 실제 CI/CD 파이프라인 데이터, 그리고 구체적인 의사결정 프레임워크입니다. 네 가지 도구 모두로 프로덕션 애플리케이션을 만들어본 경험을 바탕으로, 여러분이 정확히 어떤 것을 골라야 할지 알 수 있도록 도와드리겠습니다.
한눈에 보는 요약: npm vs Yarn vs pnpm vs Bun
자세한 내용으로 들어가기 전에, 결론부터 말씀드리겠습니다.
속도, 정확성, 모노레포 도구의 전반적인 균형을 가장 중시한다면 pnpm을 선택하세요. 날것 그대로의 설치 속도와 올인원 런타임이 최우선이라면 Bun을 선택하세요. 간단한 프로젝트에서 설정 없이 바로 쓰고 싶다면 npm을 선택하세요. 팀이 Plug'n'Play와 zero-installs에 이미 투자하고 있다면 Yarn Berry를 선택하세요.
| 기능 | npm | Yarn (Berry 4.x) | pnpm | Bun |
|---|---|---|---|---|
| 최신 버전 (2026년 2월) | 11.x | 4.x | 10.x | 1.3.x |
| 최초 릴리스 | 2010 | 2016 | 2017 | 2022 |
| 콜드 설치 속도 | 느림 | 보통 | 빠름 | 가장 빠름 |
| 디스크 효율 | 낮음 | 보통 (PnP: 높음) | 가장 높음 | 보통 |
| 모노레포 지원 | 기본 | 강력 | 가장 강력 | 성장 중 |
| 보안 기본값 | 감사(audit)만 | 설정 가능 | 엄격 (스크립트 차단) | 엄격 (스크립트 차단) |
| Node.js 호환성 | 네이티브 (Node에 동봉) | 네이티브 | 네이티브 | 98% 호환 |
| 학습 곡선 | 없음 (기본) | 보통 (PnP) | 낮음 | 낮음 |
| 락파일 형식 | JSON (package-lock.json) | YAML (yarn.lock) | YAML (pnpm-lock.yaml) | 바이너리 + 텍스트 (bun.lock) |
| node_modules 전략 | 플랫 (호이스팅) | PnP (node_modules 없음) 또는 호이스팅 | 심볼릭 링크 (엄격) | 플랫 (호이스팅) |
| Corepack 지원 | 예 | 예 | 예 | 아직 미지원 |
| 최적 용도 | 초보자, 간단한 프로젝트 | PnP를 사용하는 대형 팀 | 모노레포, 디스크 절약, 엄격한 의존성 | 속도 중시 CI, 올인원 툴킷 |
이제 각 도구가 왜 이런 평가를 받는지 하나씩 자세히 살펴보겠습니다.
후보 소개: 빠르게 살펴보기
npm, 기본값
**npm**은 모든 Node.js 설치에 함께 제공됩니다. 굳이 선택한다기보다는 물려받는 것에 가깝습니다. 버전 11에서 의미 있는 보안 개선이 이루어졌습니다. min-release-age는 게시된 지 X일도 안 된 패키지를 거부할 수 있게 해주고(타이포스쿼팅 위험을 줄여줌), npm trust는 검증된 게시자에 대해 명령어 단위로 설정을 제공합니다. 여전히 다른 모든 도구의 비교 기준이 되는 기본값이며, 작은 프로젝트에서는 충분히 잘 작동합니다.
Yarn, 클래식 vs Berry
**Yarn**은 2016년 Facebook이 npm의 초기 안정성 문제를 해결하기 위해 만들었습니다. 여기서 핵심적인 구분이 있습니다. Yarn Classic(1.x)은 유지보수 모드입니다. 새 프로젝트를 이걸로 시작하지 마세요. **Yarn Berry(2 이상, 현재 v4)**가 현대적인 버전이며, 근본적으로 다른 도구입니다. 간판 기능은 **Plug'n'Play(PnP)**로, node_modules를 완전히 없애고 임포트를 직접 매핑하는 .pnp.cjs 파일로 대체합니다. Yarn 4에는 또한 모노레포 패키지 전체에 규칙을 강제하는 JS 기반 constraints 엔진과 자동 @types 관리 기능도 포함되어 있습니다.
pnpm, 효율성 전문가
**pnpm**은 "performant npm"의 줄임말이며, 그 이름값을 톡톡히 합니다. 콘텐츠 어드레서블(content-addressable) 전역 스토어가 각 패키지 버전의 사본 하나를 디스크에 보관한 뒤, 각 프로젝트의 node_modules로 하드 링크를 연결합니다. 그 결과: 팬텀 의존성을 막는 엄격한 의존성 해석, 50~70%의 디스크 절약, 그리고 npm보다 빠른 설치 속도를 얻습니다. 버전 10에서는 과감한 결정을 내렸습니다. 라이프사이클 스크립트가 기본적으로 비활성화되고 onlyBuiltDependencies 허용 목록을 사용하게 된 것입니다. postinstall 스크립트를 실행하려면 명시적으로 옵트인해야 합니다.
Bun, 올인원 런타임
**Bun**은 단순한 패키지 매니저가 아닙니다. Zig로 작성되어 네이티브 수준의 성능을 내며, JavaScript 런타임, 번들러, 테스트 러너, 패키지 매니저를 하나로 합쳐놓았습니다. 버전 1.3에서 의존성 카탈로그(모노레포를 위한 중앙 집중식 버전 관리), bun why(패키지가 왜 설치됐는지 추적), 대화형 bun update을 도입했습니다. 설치 속도는 정말 입이 벌어질 정도인데, 곧 수치를 보여드리겠습니다.
설치 및 설정
각 도구로 시작하는 방법은 서로 다릅니다.
# npm -- ships with Node.js, nothing to install
npm --version
# Yarn -- use Corepack (recommended)
corepack enable
yarn init -2
# pnpm -- use Corepack or standalone install
corepack enable
pnpm --version
# or: npm install -g pnpm
# Bun -- standalone install
curl -fsSL https://bun.sh/install | bash
# or: brew install oven-sh/bun/bunCorepack: 패키지 매니저를 관리하는 공식 방법
대부분의 가이드가 건너뛰는 내용이 하나 있습니다. Corepack은 Node.js(v16.9 이후)에 내장되어 있으며, 패키지 매니저의 "내 컴퓨터에서는 됐는데" 문제를 해결해줍니다. package.json에 packageManager 필드를 추가하면, 팀의 모든 개발자가 자동으로 정확히 같은 버전을 사용하게 됩니다.
{
"name": "my-project",
"packageManager": "[email protected]",
"engines": {
"node": ">=22.0.0"
}
}corepack enable을 한 번 실행하면, Corepack이 pnpm이나 yarn 명령어를 가로채서 고정된 버전을 다운로드하고 사용합니다. 전역 설치를 관리할 필요도, 팀 내에서 버전이 어긋날 일도 없습니다. Bun은 아직 Corepack을 지원하지 않으므로, 다른 방법(.tool-versions 파일이나 CI 설정 같은)으로 버전을 고정해야 합니다.
CLI 명령어 비교
아래 표는 네 가지 매니저의 동등한 명령어를 정리한 것입니다. 즐겨찾기 해두세요. 분명 다시 보게 될 겁니다.
| 작업 | npm | Yarn | pnpm | Bun |
|---|---|---|---|---|
| 프로젝트 초기화 | npm init | yarn init | pnpm init | bun init |
| 모든 의존성 설치 | npm install | yarn install | pnpm install | bun install |
| 의존성 추가 | npm install lodash | yarn add lodash | pnpm add lodash | bun add lodash |
| 개발 의존성 추가 | npm install -D vitest | yarn add -D vitest | pnpm add -D vitest | bun add -d vitest |
| 의존성 제거 | npm uninstall lodash | yarn remove lodash | pnpm remove lodash | bun remove lodash |
| 패키지 업데이트 | npm update | yarn up | pnpm update | bun update |
| 스크립트 실행 | npm run dev | yarn dev | pnpm dev | bun run dev |
| 일회성 패키지 실행 | npx create-next-app | yarn dlx create-next-app | pnpx create-next-app | bunx create-next-app |
| 전역 설치 | npm install -g tsx | yarn global add tsx | pnpm add -g tsx | bun add -g tsx |
| 취약점 감사 | npm audit | yarn npm audit | pnpm audit | bun audit |
몇 가지 짚고 넘어갈 점이 있습니다. Bun은 bun install <pkg> 대신 bun add를 사용하며, bun dev만으로 스크립트를 실행할 수 있습니다(run은 생략 가능). pnpm과 Yarn도 run 키워드 없이 스크립트를 실행할 수 있습니다. npx/pnpx/yarn dlx/bunx 차이에 헷갈리는 개발자가 많으니, 이 표를 곁에 두세요.
설치 속도 벤치마크: npm vs pnpm vs Yarn vs Bun
대부분 이걸 보러 오셨을 겁니다. Apple Silicon 하드웨어에서 2026년 최신 버전으로 측정한 여러 출처의 벤치마크 데이터를 종합했습니다. 두 가지 프로젝트 규모에 대한 콜드 설치 시간(캐시 없음, 락파일 없음)입니다.
"Cold Install Speed: 50-Dependency Project (seconds)"
데이터 테이블
| "Package Manager" | "Install Time" |
|---|---|
| "npm" | 14.3 |
| "Yarn" | 6.8 |
| "pnpm" | 4.2 |
| "Bun" | 0.8 |
차트만 봐도 한눈에 알 수 있습니다. npm의 14.3초짜리 우뚝 솟은 막대 옆에서 Bun의 막대는 거의 보이지도 않습니다. pnpm과 Yarn은 그 사이에 위치하지만, 어느 쪽도 Bun의 1초 미만 콜드 설치에는 미치지 못합니다. 프로젝트가 커질수록 격차는 더 벌어지는데, 전체 벤치마크 수치를 살펴보겠습니다.
| 시나리오 | npm | Yarn | pnpm | Bun |
|---|---|---|---|---|
| 콜드 설치, 의존성 50개 | 14.3초 | 6.8초 | 4.2초 | 0.8초 |
| 콜드 설치, 의존성 800개 (모노레포) | 134.2초 | 52.3초 | 28.6초 | 4.8초 |
| 웜 설치 (캐시 + 락파일) | 5.1초 | 1.2초 | 1.8초 | 0.3초 |
벤치마크 출처: Pockit (2026년 1월), M3 MacBook Pro, Node.js 22.x. pnpm.io 벤치마크(2026년 2월 8일) 및 edbzn/package-manager-benchmarks와 교차 검증.
수치가 명확한 이야기를 들려줍니다. Bun은 의존성 50개짜리 프로젝트를 0.8초 만에 설치합니다. npm보다 17배, pnpm보다 5배 빠릅니다. 의존성 800개의 대규모 모노레포에서 Bun은 4.8초 만에 끝내지만, npm은 여전히 134초를 갈아넣고 있습니다.
Bun은 왜 이렇게 빠를까요? 세 가지 이유입니다. Zig로 작성되었고(JavaScript가 아닌 컴파일된 네이티브 코드), 일반적인 설치에 시스템 콜을 약 165,000회만 사용합니다(npm은 1,000,000회 이상). 그리고 바이너리 락파일(bun.lock)이 JSON이나 YAML보다 빠르게 파싱됩니다.
결론: 날것의 속도에서는 Bun의 승리입니다. 콜드 설치에서 Bun은 pnpm보다 35배, npm보다 1017배 빠릅니다. pnpm이 확실한 2위입니다. PnP를 쓰는 Yarn Berry는 node_modules를 없애버림으로써 이 질문 자체를 무의미하게 만듭니다. 캐시를 커밋하면(zero-installs) 설치할 것이 아예 없습니다.
디스크 사용량과 저장 효율
속도가 전부는 아닙니다. 여러 Node.js 프로젝트를 작업한다면 디스크 사용량이 빠르게 불어납니다. 각 매니저가 의존성을 어디에 저장하고 공간을 얼마나 쓰는지 살펴보겠습니다.
"Total Disk Usage per Project (MB)"
데이터 테이블
| "Size (MB)" | "Total Disk Usage" |
|---|---|
| "npm" | 890 |
| "Yarn Berry (PnP)" | 380 |
| "pnpm" | 450 |
| "Bun" | 370 |
Bun과 Yarn PnP는 차트 하단에 함께 모여 있으며, npm과 비교해 디스크 공간을 절반 이상 절약합니다. pnpm은 프로젝트 단위로 보면 중간 정도에 위치하지만, 진짜 강점은 여러 프로젝트에 걸쳐 나타납니다. 아래 표에서 확인하겠습니다.
| 매니저 | node_modules 크기 | 캐시/스토어 크기 | 프로젝트당 총 용량 | npm 대비 절약 |
|---|---|---|---|---|
| npm | 약 580 MB | 약 310 MB 캐시 | 약 890 MB | 기준선 |
| Yarn Berry (PnP) | 약 0 MB (node_modules 없음) | 약 380 MB 캐시 | 약 380 MB | 약 57% |
| pnpm | 약 150 MB (심볼릭 링크) | 약 300 MB 전역 스토어 | 약 450 MB | 약 49% |
| Bun | 약 120 MB | 약 250 MB 캐시 | 약 370 MB | 약 58% |
DevelopersVoice 벤치마크와 Pockit 분석(2025~2026) 데이터. 정확한 수치는 프로젝트마다 다릅니다.
단일 프로젝트 수치도 흥미롭지만, 진짜 이야기는 여러 프로젝트에 걸쳐 나타납니다. pnpm의 스토어를 공유 도서관이라고 생각해보세요. 모든 프로젝트가 책마다 각자의 사본을 받는 대신, 모두가 같은 도서관 카드를 공유하는 셈입니다. npm을 쓰는 Node.js 프로젝트가 10개라면 중복된 패키지가 5 GB에 달할 수 있습니다. pnpm을 쓰면 전역 스토어가 모든 것을 중복 제거하기 때문에 약 1.5 GB로 줄어듭니다.
Yarn Berry PnP는 다른 접근을 취합니다. node_modules를 완전히 없앱니다. .pnp.cjs 파일이 모든 임포트를 캐시 내 정확한 위치로 매핑합니다. zero-installs를 쓰면 캐시를 저장소에 커밋해서, 클론하면 설치 시간이 0이 됩니다.
Bun의 프로젝트당 수치는 좋아 보이지만, pnpm처럼 프로젝트 간에 패키지를 공유하지는 않습니다. 10개 프로젝트에 걸쳐 보면 pnpm의 절약 효과가 극적으로 누적됩니다.
결론: 디스크 효율에서는 pnpm이 압도적인 차이로 승리합니다. zero-install 방식을 택한다면 Yarn Berry PnP가 바짝 뒤쫓습니다. npm과 Bun은 프로젝트 간 중복 제거를 최적화하지 않습니다.
의존성 해석 심층 분석
위의 속도와 디스크 수치는 무작위가 아닙니다. 각 도구가 의존성을 해석하고 저장하는 방식의 직접적인 결과입니다. 아키텍처를 이해하면 어떤 트레이드오프를 감수하는지 예측할 수 있습니다.
npm: 호이스팅 문제
npm은 플랫 호이스팅을 사용합니다. 모든 의존성과 그 의존성의 의존성을 최상위 node_modules 폴더 하나에 설치합니다. 여기서 팬텀 의존성이라는 문제가 생깁니다. package.json에 lodash를 추가한 적이 없어도 다른 패키지가 lodash를 끌어와서 npm이 최상위로 호이스팅했기 때문에, 코드에서 import 'lodash'가 가능해지는 것입니다.
이건 잘 작동합니다… 전이 의존성 업데이트로 lodash가 사라지기 전까지는요. 명시적으로 설치한 적도 없는 패키지에 의존하고 있었기 때문에, 아무 경고 없이 프로덕션에서 코드가 깨집니다.
Yarn Berry: node_modules여 안녕
Yarn Berry의 Plug'n'Play는 가장 급진적인 접근을 취합니다. node_modules가 아예 없습니다. .pnp.cjs 파일에 모든 패키지를 디스크상의 정확한 위치로 매핑한 지도가 담깁니다. 덕분에 더 빠른 조회(파일 시스템 순회 불필요), 호이스팅 문제 없음, 그리고 zero-installs 옵션을 얻습니다.
단점은? 일부 패키지는 node_modules가 존재한다고 가정합니다. 호환성 문제가 생기면 .yarnrc.yml에서 nodeLinker: node-modules로 폴백할 수 있습니다. 하지만 그러면 PnP의 이점을 포기하게 됩니다.
pnpm: 설계부터 엄격하게
pnpm은 중간 길을 갑니다. node_modules 디렉터리를 만들기 때문에(도구 호환성이 높음) 구조는 근본적으로 다릅니다. 패키지는 node_modules/.pnpm에 위치하고 심볼릭 링크로 제자리에 연결됩니다. package.json에 명시적으로 선언한 패키지만 최상위에서 접근할 수 있습니다.
즉 팬텀 의존성이 없습니다. package.json에 추가하지 않았다면 임포트할 수 없습니다. 코드는 개발 중에 빠르게 실패하며, 석 달 뒤 프로덕션에서 원인 모르게 깨지는 일이 없습니다.
Bun: 빠르지만 플랫
Bun은 npm과 같은 플랫 호이스팅 전략을 사용합니다. 팬텀 의존성을 해결하지 않으며, 정확성보다 날것의 속도를 우선시합니다. npm에서 넘어온다면, Bun은 설치에 있어 드롭인 대체재지만 같은 의존성 해석 리스크를 물려받게 됩니다.
결론: 의존성 정확성에서는 pnpm의 승리입니다. 엄격한 해석 덕분에 npm과 Bun이 조용히 숨기는 실제 버그를 잡아냅니다. Yarn Berry PnP는 더 엄격하지만 생태계 호환성 작업이 더 필요합니다. 의존성 정확성이 팀에 중요하다면(그래야 합니다), pnpm이 실용적인 선택입니다.
모노레포와 워크스페이스 지원
단일 저장소에서 여러 패키지를 관리한다면 워크스페이스 지원은 중요한 결정 요인입니다. 각 도구가 모노레포를 어떻게 구성하는지 살펴보겠습니다.
// npm and Bun: package.json
{
"workspaces": ["packages/*", "apps/*"]
}# pnpm: pnpm-workspace.yaml
packages:
- "packages/*"
- "apps/*"# Yarn Berry: package.json workspaces field
# plus .yarnrc.yml for constraints
enableGlobalCache: false
nodeLinker: pnp워크스페이스 기능 비교
| 기능 | npm | Yarn | pnpm | Bun |
|---|---|---|---|---|
| 워크스페이스 프로토콜 (workspace:*) | 아니오 | 예 | 예 | 예 |
| 워크스페이스 필터링 (--filter) | 제한적 (--workspace) | yarn workspace <name> | pnpm --filter <pattern> | bun --filter <pattern> |
| 워크스페이스 간 연결 | 자동 | 자동 | 자동 | 자동 |
| 빌드 오케스트레이션 | 수동 | 예 (플러그인) | Turborepo/Nx 경유 | Turborepo/Nx 경유 |
| 의존성 constraints | 아니오 | JS constraints 엔진 | 기본 엄격 | 아니오 |
| 카탈로그 (중앙 집중 버전) | 아니오 | 아니오 | 예 (catalog: 프로토콜) | 예 (v1.3) |
pnpm의 필터링이 가장 성숙합니다. 이름, 디렉터리, 의존성 그래프별로 특정 패키지에 명령을 실행할 수 있습니다. pnpm --filter @app/web... build는 해당 패키지와 그 모든 의존성에 대해 빌드를 실행합니다. Yarn 4의 JS constraints 엔진은 독보적인데, 모노레포 전체에 정책을 강제하는 JavaScript 규칙을 작성할 수 있습니다(예: "모든 패키지가 같은 버전의 React를 써야 한다").
모노레포에서의 pnpm vs Yarn은 철학의 차이로 귀결됩니다. pnpm은 엄격한 의존성 모델로 정확성을 강제하고, Yarn은 constraints 엔진으로 강제합니다. 둘 다 작동합니다. pnpm 쪽이 설정이 덜 필요합니다.
결론: 모노레포 워크플로에서는 pnpm의 승리입니다. 필터링, 엄격한 의존성 해석, 워크스페이스 프로토콜 지원이 가장 성숙합니다. Yarn Berry는 독보적인 constraints 엔진으로 강력한 2위입니다. npm 워크스페이스도 작동하지만 고급 기능이 부족합니다. Bun은 v1.3의 의존성 카탈로그로 빠르게 따라잡고 있습니다.
보안 비교
npm 패키지를 노린 공급망 공격은 실재하며 점점 커지는 우려입니다. 각 도구가 여러분을 어떻게 보호하는지 살펴보겠습니다.
| 기능 | npm | Yarn | pnpm | Bun |
|---|---|---|---|---|
| 취약점 감사 | npm audit | yarn npm audit | pnpm audit | bun audit (최신) |
| Postinstall 스크립트 | 기본적으로 모두 실행 | 설정 가능 (enableScripts) | 기본 차단 (v10+) | 기본 차단 (trustedDependencies) |
| 공급망 보호 | min-release-age, npm trust (v11) | 플러그인 기반 | 엄격한 락파일, 팬텀 의존성 없음 | trustedDependencies 허용 목록 |
| 락파일 체크섬 | 예 (SHA-512) | 예 | 예 | 예 |
| Overrides/resolutions | overrides 필드 | resolutions 필드 | overrides + pnpm.overrides | overrides 필드 |
가장 큰 차별점은 postinstall 스크립트 처리입니다. npm install을 실행하면 npm은 기본적으로 모든 패키지의 모든 라이프사이클 스크립트(install, postinstall, prepare)를 실행합니다. 즉, 침해당한 패키지는 설치 순간에 여러분 컴퓨터에서 임의의 코드를 실행할 수 있습니다.
pnpm 10과 Bun은 이 기본값을 뒤집었습니다. onlyBuiltDependencies(pnpm)나 trustedDependencies(Bun)에 명시적으로 허용 목록을 등록하지 않으면 스크립트가 차단됩니다. 근본적인 보안 개선입니다. npm 11의 min-release-age는 영리한 추가 기능인데, 최근 N일 이내에 게시된 패키지를 거부해서 타이포스쿼팅 공격의 창을 줄일 수 있습니다. 다만 옵트인 방식이지 기본값은 아닙니다.
결론: 보안에서는 pnpm과 Bun이 앞서 있습니다. 둘 다 라이프사이클 스크립트를 기본적으로 차단하며, 이는 공급망 공격에 맞서는 가장 영향력 있는 단일 보호 조치입니다. npm 11의 min-release-age는 영리한 추가 기능이지만 옵트인입니다. Yarn은 유연하지만 수동 설정이 필요합니다.
CI/CD와 빌드 성능
패키지 매니저 선택은 CI/CD 파이프라인 비용에 직접적인 영향을 미칩니다. 설치가 빠르면 빌드가 짧아지고, 인프라 비용이 줄어듭니다. GitHub Actions 벤치마크 데이터입니다.
"GitHub Actions Total Job Time"
데이터 테이블
| "Package Manager" | "Total Job Time" |
|---|---|
| "npm" | 154 |
| "pnpm" | 128 |
| "Bun" | 112 |
Bun은 npm과 비교해 GitHub Actions 작업마다 42초를 줄여줍니다. 하루에 수십 번의 빌드를 돌린다면 의미 있는 차이입니다. pnpm은 중간 정도이며, npm보다 약 26초 빠릅니다. 설치 단계만 따로 떼어낸 전체 내역입니다.
| 매니저 | 설치 단계 | 총 작업 시간 |
|---|---|---|
| npm | 약 45초 | 2분 34초 |
| pnpm | 약 28초 | 2분 08초 |
| Bun | 약 8초 | 1분 52초 |
출처: Pockit GitHub Actions 벤치마크 (2026년 1월). 표준 Node.js 빌드 + 테스트 파이프라인.
각 매니저는 CI에서 서로 다른 캐싱 전략을 가집니다. GitHub Actions용 프로덕션 수준의 pnpm 설정입니다.
# .github/workflows/ci.yml
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: pnpm testDocker 최적화의 핵심은 레이어 캐싱입니다. 소스 코드보다 락파일을 먼저 복사해서 의존성 설치가 빌드 간에 캐시되도록 하세요. 이는 네 가지 매니저 모두에 해당합니다.
이제 돈 이야기를 해보겠습니다. 팀이 하루에 CI 빌드를 50회 실행하고 npm에서 pnpm으로 전환해서 빌드당 26초를 절약한다면, 하루에 21.6분을 아끼는 셈입니다. 한 달이면 CI 시간 10.8시간입니다. 일반적인 GitHub Actions 요금(Linux 러너 분당 $0.008)으로 치면 약 월 $5.18로, 작은 팀에는 소소하지만 수백 건의 빌드를 돌리는 조직에서는 절약 효과가 선형으로 커집니다. 진짜 이득은 개발자 시간입니다. 피드백 루프가 빨라지면 생산성이 높아집니다.
배포 플랫폼이 빌드 효율을 어떻게 측정하는지 더 깊이 알고 싶다면, 패키지 매니저 선택은 당길 수 있는 가장 큰 레버 중 하나입니다.
결론: CI에서는 Bun이 가장 빠릅니다. 하지만 속도, 캐싱, 생태계 호환성의 균형에서는 pnpm이 가장 좋습니다. 진짜 절약 효과는 CI 파이프라인에서의 빠른 설치, 특히 규모가 커질수록 옵니다.
프레임워크 호환성
패키지 매니저를 진공 상태에서 고르지 않습니다. 특정 프레임워크와 프로젝트에 맞춰 고릅니다. 실제로 무엇이 작동하고 프레임워크 메인테이너가 무엇을 권장하는지 살펴보겠습니다.
| 프레임워크 | 기본 PM | pnpm 지원 | Bun 지원 | 참고 |
|---|---|---|---|---|
| Next.js | npm (create-next-app) | 완전 지원 (Vercel CI가 네이티브 지원) | 완전 지원 (--use-bun 플래그) | Next.js 커뮤니티에서 pnpm이 널리 쓰임 |
| Remix | npm | 완전 지원 | 완전 지원 | 모노레포에는 pnpm 권장 |
| Astro | npm | 완전 지원 (문서에서 pnpm 예제를 먼저 제시) | 완전 지원 | 커뮤니티가 pnpm을 강하게 선호 |
| SvelteKit | npm | 완전 지원 | 완전 지원 | pnpm이 흔히 쓰임 |
| Nuxt | npm | 완전 지원 (문서에 pnpm 예제) | 완전 지원 | 공식 문서에 pnpm 예제 |
| Vite | npm | 완전 지원 | 완전 지원 | 모든 매니저와 작동 |
좋은 소식입니다. 모든 현대 프레임워크가 네 가지 매니저 모두와 작동합니다. 미묘한 차이는 Bun 호환성과 Yarn PnP에 있습니다.
Bun은 98% npm 호환성을 주장합니다. 나머지 2%에는 node-gyp를 쓰는 일부 네이티브 모듈, npm의 동작을 가정하는 특정 postinstall 스크립트, peer 의존성 해석의 엣지 케이스가 포함됩니다. 결정하기 전에 여러분의 특정 프로젝트에서 테스트하세요.
Yarn PnP는 호환성 문제가 더 넓습니다. 일부 패키지는 디스크에 node_modules가 존재한다고 가정합니다. 문제가 생기면 .yarnrc.yml에서 nodeLinker: node-modules를 폴백으로 설정할 수 있지만, PnP의 이점을 포기하게 됩니다.
빌드 도구 선택을 생각할 때 패키지 매니저는 한 조각에 불과합니다. 하지만 하루에 수십 번씩 상호작용하는 조각이므로, 제대로 고를 가치가 있습니다.
결론: npm이 최고의 호환성을 가집니다(범용 기본값). pnpm이 실질적인 호환성 문제 없이 바짝 뒤쫓는 2위입니다. Bun은 98%의 경우에 작동합니다. Yarn PnP는 호환성 테스트가 필요합니다.
Bun의 프로덕션 준비 상태: 2026년 현실 점검
모든 글이 Bun을 미래라며 띄우거나 너무 미성숙하다며 깎아내립니다. 저희의 솔직한 평가입니다.
2026년에 잘 작동하는 것:
bun install은 대부분의 npm 프로젝트와 드롭인 호환됩니다. 런타임을 바꿀 필요 없이, Node.js와 함께 Bun을 패키지 매니저로만 쓰면 됩니다- 바이너리 락파일(
bun.lockb)은 더 나은 git diff를 위해 텍스트 기반bun.lock으로 교체되었습니다 - 의존성 카탈로그와
bun why로 pnpm 수준의 모노레포 도구에 가까워졌습니다 - Anthropic은 Claude Code 도구 제작에 Bun을 사용합니다. 다른 주목할 만한 회사들도 내부 도구에 Bun을 도입했습니다
알려진 엣지 케이스:
node-gyp를 쓰는 네이티브 모듈은 실패할 수 있습니다- 일부 postinstall 스크립트는 npm 고유의 동작을 가정합니다
- Windows 지원은 Linux/macOS보다 최신이며 실전 검증이 덜 됐습니다
- peer 의존성 해석에서 npm과 가끔 차이가 있습니다
- 일부 CI 환경에서는 Bun을 명시적으로 설치해야 합니다(npm처럼 사전 설치되어 있지 않음)
현실적인 도입 경로: Bun 런타임으로 전환하지 않고 bun install만 쓸 수 있습니다. Bun의 속도 이점을 가장 낮은 리스크로 얻는 방법입니다. 코드는 여전히 Node.js에서 실행되고, 테스트도 기존 러너를 쓰지만, node_modules는 10배 빠르게 채워집니다. 이게 잘 작동하면 점진적으로 Bun 툴킷의 더 많은 부분을 도입하면 됩니다.
Bun은 2026년에 프로덕션에 쓸 만한가? 패키지 매니저로서는, 테스트를 거치면 예. Node.js의 완전한 런타임 대체재로서는, 여러분의 특정 의존성에 맞춰 신중하게 평가하세요.
마이그레이션 가이드
npm에서 pnpm으로 (가장 인기 있는 마이그레이션)
가장 쉬운 마이그레이션 경로입니다. pnpm은 npm의 락파일을 네이티브로 읽습니다.
- pnpm 설치:
corepack enable을 실행한 뒤package.json에"packageManager": "[email protected]"을 추가 - 락파일 가져오기:
pnpm import(package-lock.json을pnpm-lock.yaml로 변환) - 정리:
node_modules와package-lock.json삭제 - 설치:
pnpm install - 모든 것 테스트: 빌드, 테스트, 개발 서버 실행
- CI 설정 업데이트: GitHub Actions에서 pnpm/action-setup으로 전환
npm에서 Bun으로 (가장 빠른 경로)
더 간단합니다. Bun은 package-lock.json을 직접 읽습니다.
- Bun 설치:
curl -fsSL https://bun.sh/install | bash - 실행:
bun install(bun.lock생성) - 테스트: 일부 postinstall 스크립트는
package.json의trustedDependencies가 필요할 수 있음 - CI 업데이트: Bun 설치 단계 추가
마이그레이션 난이도 요약
| 마이그레이션 경로 | 난이도 | 예상 시간 | 핵심 명령어 |
|---|---|---|---|
| npm에서 pnpm으로 | 쉬움 | 30분 | pnpm import |
| npm에서 Bun으로 | 쉬움 | 15분 | bun install |
| Yarn Classic에서 pnpm으로 | 쉬움 | 30분 | pnpm import |
| Yarn Classic에서 Yarn Berry로 | 보통 | 1~2시간 | yarn set version berry |
| npm에서 Yarn Berry (PnP)로 | 어려움 | 2~4시간 | PnP 호환성 테스트 필요 |
프로 팁: 스프린트 중간에 마이그레이션하지 마세요. 시간을 따로 내고, 전체 빌드 파이프라인을 테스트하고, 롤백 계획을 세워두세요. 대부분의 팀에게 npm에서 pnpm으로의 마이그레이션은 정말 고통이 없습니다.
무엇을 언제 쓸까: 의사결정 프레임워크
모든 독자가 기다리던 섹션입니다. 시나리오별 구체적인 권장 사항입니다.
| 필요한 것 | 선택 | 이유 |
|---|---|---|
| 설정 없이 바로 작동 | npm | Node에 동봉, 범용 호환성 |
| 최대 설치 속도 | Bun | 대안보다 3~17배 빠름 |
| 여러 프로젝트에 걸친 디스크 절약 | pnpm | 콘텐츠 어드레서블 스토어로 50~70% 절약 |
| 패키지 10개 이상의 모노레포 | pnpm | 최고의 필터링, 엄격한 의존성, 워크스페이스 프로토콜 |
| Zero-installs (클론 후 설치 없음) | Yarn Berry | PnP + 커밋된 캐시 = 설치 시간 0 |
| 최대 보안 기본값 | pnpm 또는 Bun | 둘 다 라이프사이클 스크립트를 기본 차단 |
| Corepack으로 팀 표준화 | pnpm 또는 Yarn | packageManager 필드로 네이티브 Corepack 지원 |
| Next.js 프로젝트 (모든 규모) | pnpm | Vercel이 네이티브 지원, 빠른 CI, 엄격한 의존성 |
| 가장 빠른 CI/CD 파이프라인 | Bun | 벤치마크에서 최저 총 작업 시간 |
| 컴플라이언스가 필요한 엔터프라이즈 | pnpm | 가장 엄격한 의존성 해석, 팬텀 의존성 없음 |
| 작은 개인 프로젝트 | npm | 주말 프로젝트에 복잡함을 더할 필요가 있나? |
| 첨단 올인원 툴킷 | Bun | 런타임 + PM + 번들러 + 테스트 러너를 하나로 |
팀 규모별 가이드
| 팀 규모 | 권장 | 이유 |
|---|---|---|
| 1인 개발자 | npm 또는 Bun | 단순함(npm) 또는 속도(Bun). 과도한 설계는 금물. |
| 소규모 팀 (2~5명) | pnpm | 속도, 엄격함, Corepack 표준화의 균형 |
| 중규모 팀 (5~20명) | pnpm | 모노레포 지원, 엄격한 의존성이 통합 버그를 방지 |
| 엔터프라이즈 (20명+) | pnpm 또는 Yarn Berry | 엄격함은 pnpm; PnP 거버넌스와 constraints가 필요하면 Yarn Berry |
Techsy가 패키지 매니저를 선택하는 방법
Techsy에서는 네 가지 패키지 매니저 모두로 프로덕션 애플리케이션을 출시해봤습니다. 몸으로 배운 교훈입니다.
-
대부분의 클라이언트 프로젝트에서 pnpm이 기본입니다. 엄격한 의존성 해석 덕분에 팬텀 의존성 문제를 프로덕션에 도달하기 전에 잡아냅니다. 팀이 동시에 10개 이상의 프로젝트를 진행할 때 디스크 절약이 중요합니다. 그리고 Corepack 덕분에 새 개발자 온보딩이 매끄럽습니다. 저장소를 클론하고
pnpm install을 실행하면 모든 것이 그냥 작동합니다. -
Bun은 내부 도구, CLI 스크립트, 속도가 가장 중요한 프로토타입에 사용합니다. 일부 클라이언트 프로젝트에서는 Node.js 런타임과 함께
bun install을 쓰기도 하는데, 완전한 Bun 런타임에 올인하지 않고도 Bun의 설치 속도를 얻을 수 있습니다. -
npm은 빠른 프로토타입과 팀이 이미 npm 기반이라 마이그레이션 비용이 정당화되지 않는 클라이언트 프로젝트에 사용합니다. npm도 괜찮습니다. 모든 것을 최적화할 필요는 없습니다.
-
Yarn Berry는 zero-installs가 필요하거나 기존 PnP 인프라가 있는 특정 클라이언트 환경에 권장합니다. 특수한 요구를 위한 특수한 도구입니다.
새 프로젝트에 대한 저희의 표준 프로세스: 프로젝트의 모노레포 요구사항을 평가하고, CI 파이프라인 제약을 확인하고, 팀의 숙련도를 고려한 뒤, 특별한 이유가 없으면 pnpm을 기본으로 합니다.
새 프로젝트를 세팅 중이고 첫날부터 도구를 제대로 갖추고 싶으신가요? 저희 팀은 네 가지 패키지 매니저 모두로 프로덕션 애플리케이션을 출시했습니다. 무료 아키텍처 상담을 받아보세요.
최종 결론: 2026년의 npm vs Yarn vs pnpm vs Bun
| 카테고리 | 승자 | 차점 | 이유 |
|---|---|---|---|
| 설치 속도 | Bun | pnpm | Bun은 pnpm보다 3 |
| 디스크 효율 | pnpm | Yarn Berry (PnP) | 콘텐츠 어드레서블 스토어로 프로젝트 간 50~70% 절약 |
| 모노레포 지원 | pnpm | Yarn Berry | 최고의 필터링, 워크스페이스 프로토콜, 엄격한 의존성 |
| 보안 기본값 | 공동: pnpm과 Bun | Yarn Berry | 둘 다 라이프사이클 스크립트를 기본 차단 |
| 생태계 호환성 | npm | pnpm | npm은 100% 호환의 범용 기본값 |
| 개발자 경험 | pnpm | Bun | 빠르고, 엄격하고, 훌륭한 에러 메시지 |
| CI/CD 성능 | Bun | pnpm | GitHub Actions에서 최저 총 작업 시간 |
| 학습 곡선 | npm | Bun | npm은 배울 것이 없고; Bun은 직관적 |
| 종합 (2026) | pnpm | Bun | 속도, 정확성, 성숙도의 최고 균형 |
2026년에 패키지 매니저를 고른다면, pnpm이 대부분의 팀에게 가장 안전한 선택입니다. 빠르고, 디스크 효율이 높고, 의존성에 엄격하며, 최고의 모노레포 도구를 갖췄습니다. Bun은 흥미로운 미래로, 속도가 최우선이거나 올인원 툴킷을 원할 때 쓰세요. npm도 괜찮습니다. 도구에 대해 고민하고 싶지 않은 간단한 프로젝트라면요. Yarn Berry는 PnP의 독특한 이점을 원하는 팀을 위한 특수한 선택입니다.
최고의 패키지 매니저는 팀 전체가 합의하는 것입니다. 프로젝트의 요구를 평가하고, 하나를 고르고, Corepack으로 고정한 뒤, 빌드를 시작하세요.
출처
- npm 문서, 공식 npm CLI 레퍼런스와 가이드
- pnpm 문서, 벤치마크와 마이그레이션 가이드를 포함한 공식 pnpm 문서
- Yarn 문서, 공식 Yarn Berry (v4) 문서와 Plug'n'Play 레퍼런스
- Bun 문서, 런타임, 패키지 매니저, 도구를 다루는 공식 Bun 문서
- pnpm.io 벤치마크, pnpm의 공식 설치 속도 벤치마크 (2026년 2월 8일)
- edbzn/package-manager-benchmarks, npm, Yarn, pnpm, Bun을 비교하는 오픈소스 벤치마크 스위트
자주 묻는 질문
가장 빠른 JavaScript 패키지 매니저는 무엇인가요?
Bun이 압도적인 차이로 가장 빠릅니다. M3 MacBook Pro 벤치마크에서 Bun은 의존성 50개 프로젝트를 0.8초 만에 설치하며, npm은 14.3초가 걸립니다. pnpm은 같은 프로젝트에서 4.2초로 가장 빠른 Node.js 네이티브 옵션입니다.
pnpm이 npm보다 나은가요?
대부분의 프로젝트에서 그렇습니다. pnpm은 더 빠르고, 디스크 공간을 덜 쓰며(프로젝트 간 50~70% 절약), 팬텀 의존성을 막고, 모노레포 지원이 더 좋습니다. 트레이드오프: 초기 학습 곡선이 약간 더 가파르고, 플랫 node_modules를 가정하는 레거시 패키지에서 드문 엣지 케이스가 있습니다.
Bun은 2026년에 프로덕션에 쓸 만한가요?
패키지 매니저로서는 그렇습니다. bun install은 Node.js 프로젝트와 작동하며 98% npm 호환입니다. 런타임을 바꾸지 않고 Bun을 패키지 매니저로 쓸 수 있습니다. Node.js의 완전한 런타임 대체재로서는, 결정하기 전에 특정 의존성을 신중하게 테스트하세요.
npm에서 pnpm으로 전환해야 하나요?
여러 프로젝트나 모노레포에서 작업한다면 그렇습니다. 마이그레이션은 거의 드롭인 수준입니다. pnpm import로 락파일을 변환하고, node_modules를 삭제하고, pnpm install을 실행하면 됩니다. 작은 단일 프로젝트 하나에 npm이 문제를 일으키지 않는다면 서두를 필요는 없습니다.
Bun이 npm을 대체하나요?
Bun은 패키지 매니저로서 npm을 대체할 수 있지만, 그 이상입니다. JavaScript 런타임, 번들러, 테스트 러너이기도 합니다. Node.js를 런타임으로 유지하면서 bun install만 쓸 수도 있습니다. Bun이 가장 잘하는 것(빠른 설치)에 Bun을 쓰고, 나머지는 기존 스택을 유지한다고 생각하면 됩니다.
Yarn은 2026년에도 의미가 있나요?
Yarn Berry(v4)는 Plug'n'Play와 zero-installs를 원하는 팀에게 의미가 있습니다. JS constraints 엔진은 정말 독보적입니다. 하지만 Yarn Classic(v1)은 유지보수 모드이므로 마이그레이션해야 합니다. Yarn Classic을 쓰고 있다면 pnpm이나 Yarn Berry로 옮기세요.
팬텀 의존성이란 무엇인가요?
package.json에 추가한 적 없는데도 코드에서 임포트할 수 있는 패키지입니다. npm과 Yarn Classic이 전이 의존성을 node_modules 최상위로 호이스팅하기 때문에 생깁니다. 의존성 업데이트로 그 전이 패키지가 사라지기 전까지는 코드가 작동하다가, 프로덕션에서 깨집니다. pnpm은 엄격한 의존성 해석으로 이를 방지합니다.
모노레포에 가장 좋은 패키지 매니저는 무엇인가요?
pnpm입니다. 가장 성숙한 워크스페이스 필터링(--filter), 패키지 간 엄격한 의존성 격리, 워크스페이스 프로토콜 지원(workspace:*)을 갖췄습니다. Yarn Berry는 constraints 엔진으로 강력한 2위입니다. Bun은 v1.3의 의존성 카탈로그로 따라잡고 있습니다.
Corepack이란 무엇인가요?
패키지 매니저 버전을 관리하는 Node.js 내장 도구(v16.9 이후)입니다. package.json에 "packageManager": "[email protected]"을 추가하고 corepack enable을 실행하세요. Corepack은 모든 개발자와 CI 러너가 정확히 그 버전을 사용하도록 보장합니다. 수동 설치도, 버전 어긋남도 없습니다.
기존 npm 프로젝트에서 Bun을 쓸 수 있나요?
네. package.json이 있는 어떤 프로젝트에서든 bun install을 실행하세요. Bun은 package-lock.json과 yarn.lock 파일을 읽습니다. 프로젝트 구조를 바꿀 필요 없고, 코드는 여전히 Node.js에서 실행됩니다.
npm에서 pnpm으로 어떻게 마이그레이션하나요?
pnpm import으로 package-lock.json을 pnpm-lock.yaml로 변환하고, node_modules와 package-lock.json을 삭제하고, pnpm install을 실행한 뒤 빌드 파이프라인을 테스트하세요. 대부분의 프로젝트에서 전체 과정은 약 30분 걸립니다.
Next.js는 어떤 패키지 매니저를 쓰나요?
Next.js는 네 가지 모두와 작동합니다. create-next-app은 npm이 기본이지만 --use-pnpm, --use-yarn, --use-bun 플래그를 지원합니다. Vercel의 CI 플랫폼은 pnpm을 네이티브로 지원하며, Next.js 커뮤니티는 엄격한 의존성 해석과 모노레포 지원 때문에 pnpm을 강하게 선호합니다.