bun、npm、pnpm、yarnはすべてJavaScript/TypeScriptプロジェクトにおける依存関係の管理、スクリプト実行、ワークスペース対応などの機能を提供するパッケージマネージャーです。これらのツールは共通の目標を持ちながらも、内部アーキテクチャ、パフォーマンス特性、キャッシュ戦略、ワークスペースモデルにおいて明確な違いがあります。特に、bunはJavaScriptランタイムとしての側面も持ち、他の3つとは根本的に異なる設計思想に基づいています。
現代のフロントエンド開発において、パッケージマネージャーは単なる依存関係解決ツールではなく、開発体験全体を左右する基盤技術です。bun、npm、pnpm、yarnはそれぞれ独自のアプローチでこの課題に取り組んでおり、プロジェクトの規模、パフォーマンス要件、メンテナンス方針によって最適な選択肢は変わります。本稿では、実際の開発シナリオに基づいた技術的比較を行います。
各パッケージマネージャーは、依存関係をどのように保存し、解決するかという点で根本的に異なります。
npm は従来の node_modules フォルダに依存関係をフラット化して保存します。これは最も広く理解されているモデルですが、ディスク使用量が膨大になりやすく、重複インストールが発生しやすいという欠点があります。
# npm install の結果
node_modules/
├── lodash/
├── react/
└── react-dom/ # 依存関係が重複している可能性あり
pnpm はグローバルストアに依存関係を一元保存し、プロジェクト内にはシンボリックリンクとハードリンクを配置します。これにより、同一バージョンのパッケージは1回しか保存されず、ディスク使用量を劇的に削減できます。
# pnpm install の結果
node_modules/
├── .pnpm/
│ ├── react@18.2.0/node_modules/react → /global-store/react/18.2.0
│ └── react-dom@18.2.0/node_modules/react-dom → /global-store/react-dom/18.2.0
└── react → .pnpm/react@18.2.0/node_modules/react
yarn は2つのモードをサポートします。デフォルトでは node_modules を使用しますが、PnP(Plug'n'Play)モードを有効にすると、node_modules を完全に排除し、.pnp.cjs または .pnp.js ファイルを通じて依存関係を解決します。
# yarn with PnP
.pnp.cjs # 依存関係のマップファイル
# node_modules フォルダは存在しない
bun は独自のバイナリフォーマットで依存関係をキャッシュし、node_modules は作成しません。代わりに、.bun/install/cache/ にバイナリ形式で保存し、実行時に直接読み込みます。
# bun install の結果
.bun/
└── install/
├── cache/
└── node_modules -> シンボリックリンク(実際の内容はキャッシュ内)
速度はパッケージマネージャー選定の重要な要素です。以下は新規プロジェクトでの install コマンドの典型的な動作です。
npm
# npm
npm install
# キャッシュ: ~/.npm
# 並列ダウンロードだが、node_modulesの書き込みがボトルネックに
pnpm
# pnpm
pnpm install
# グローバルストアからハードリンクでコピーするため、非常に高速
# キャッシュ: ~/.pnpm-store
yarn
# yarn
yarn install
# ゼロインストールが有効なら、キャッシュから直接復元
# キャッシュ: .yarn/cache または ~/.yarn/berry
bun
# bun
bun install
# Zigで書かれた高速なHTTPクライアントとバイナリキャッシュにより、
# 他のツールより桁違いに高速(公式ベンチマーク参照)
大規模プロジェクトでは、複数のパッケージを単一リポジトリで管理するワークスペース機能が重要です。
npm
// package.json
{
"workspaces": ["packages/*"]
}
npm install
# packages/a と packages/b の依存関係を hoist(上位に集約)
pnpm
# pnpm-workspace.yaml
packages:
- 'packages/*'
pnpm install
# 厳格なノードモジュール構造を維持しつつ、ワークスペース間の依存を解決
yarn
# .yarnrc.yml
workspaces:
- packages/*
yarn install
# PnPモードでは、ワークスペース間の依存も .pnp.cjs で解決
bun
// bunfig.toml
[install]
workspace = true
bun install
# ワークスペース対応は比較的新しく、まだ発展途上
スクリプト実行の速度とUXも重要な差別化要因です。
npm
npm run dev
# 標準的だが、起動オーバーヘッドが大きい
pnpm
pnpm run dev
# npmと互換性がありながら、より高速な起動
yarn
yarn dev
# プラグインによりカスタマイズ可能
bun
bun run dev
# JavaScript/TypeScriptを直接実行可能(Babel/TS-Node不要)
bun index.ts # 直接実行可能
npm と yarn は package-lock.json / yarn.lock で依存関係の正確なバージョンを固定します。
pnpm は pnpm-lock.yaml を使用し、さらに依存関係の階層構造まで厳密に記録します。
bun は bun.lockb(バイナリフォーマット)を使用し、高速な読み書きを実現します。
# 全てのツールで lock ファイルの整合性チェックが可能
npm ci # npm
pnpm install --frozen-lockfile # pnpm
yarn install --immutable # yarn
bun install --frozen-lockfile # bun
bunnpmpnpmyarn(PnP + Zero-installs)| 特徴 | bun | npm | pnpm | yarn |
|---|---|---|---|---|
| 主な強み | 高速実行、オールインワン | 標準互換性、安定性 | ディスク効率、セキュリティ | カスタマイズ性、PnP |
| node_modules | 仮想(実体なし) | 通常 | リンクのみ | 任意(PnPで不要) |
| ロックファイル | bun.lockb(バイナリ) | package-lock.json | pnpm-lock.yaml | yarn.lock |
| ワークスペース | 基本対応 | 成熟 | 優れた分離 | 最も柔軟 |
| TypeScript実行 | 直接可能 | 別途ts-node必要 | 別途ts-node必要 | 別途ts-node必要 |
bunを試すnpmを選ぶpnpmが最適yarn(PnPモード)を検討どのツールも日々進化しており、プロジェクトのニーズに合わせて柔軟に選択することが重要です。一度選んだからといって固定する必要はなく、移行パスも各ツールで提供されています。
pnpmはディスク使用量を最小限に抑えつつ、厳格なノードモジュール構造を維持したい場合に最適です。シンボリックリンクとハードリンクを活用した効率的なストレージ戦略により、複数プロジェクト間での依存関係の重複を排除できます。セキュリティと再現性を重視するチームや、CI環境でのキャッシュ効率を最大化したい場合に推奨されます。
npmはNode.jsの標準パッケージマネージャーであり、最大のエコシステム互換性と安定性を提供します。企業環境や長期保守が求められるプロジェクト、または他のパッケージマネージャー特有の機能を必要としないシンプルなワークフローに適しています。ワークスペース機能(npm workspaces)も成熟しており、大規模モノレポにも対応可能です。
yarn(特にYarn Berry以降)は高度にカスタマイズ可能なプラグインシステムとゼロインストール(Zero-installs)機能を活用したいプロジェクトに適しています。PnP(Plug'n'Play)モードによるnode_modules不要の依存解決や、ワークスペース間の依存関係の細かい制御が必要な大規模モノレポ開発でその真価を発揮します。ただし、設定の複雑さと学習コストが高い点に留意が必要です。
bunは極めて高速なインストールとスクリプト実行を必要とする開発環境に最適です。TypeScriptやJSXのプリコンパイルなしで直接実行できる点や、内蔵HTTPサーバー、テストランナーなどオールインワンの開発体験を求める場合に選択します。ただし、Node.js互換性が完全ではないため、ネイティブアドオンや特定のNode APIに依存するプロジェクトでは注意が必要です。
简体中文 | 日本語 | 한국어 | Italiano | Português Brasileiro
Fast, disk space efficient package manager:
node_modules are linked from a single content-addressable storage.package.json.pnpm-lock.yaml.To quote the Rush team:
Microsoft uses pnpm in Rush repos with hundreds of projects and hundreds of PRs per day, and we’ve found it to be very fast and reliable.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Support this project by becoming a sponsor.
pnpm uses a content-addressable filesystem to store all files from all module directories on a disk. When using npm, if you have 100 projects using lodash, you will have 100 copies of lodash on disk. With pnpm, lodash will be stored in a content-addressable storage, so:
pnpm update will only add 1 new file to the storage.As a result, you save gigabytes of space on your disk and you have a lot faster installations!
If you'd like more details about the unique node_modules structure that pnpm creates and
why it works fine with the Node.js ecosystem, read this small article: Flat node_modules is not the only way.
💖 Like this project? Let people know with a tweet
For installation options visit our website.
Just use pnpm in place of npm/Yarn. E.g., install dependencies via:
pnpm install
For more advanced usage, read pnpm CLI on our website, or run pnpm help.
pnpm is up to 2x faster than npm and Yarn classic. See all benchmarks here.
Benchmarks on an app with lots of dependencies: