pnpm vs npm 徹底比較

pnpm の詳細npm の詳細
AI生成コンテンツ

この記事はAIによって生成されました。内容の正確性は保証されません。最新の情報は公式ドキュメントをご確認ください。

pnpm vs npm 徹底比較 — どちらのパッケージマネージャーを選ぶべきか

1. 結論

ディスク効率・速度・厳密な依存関係管理を重視するなら pnpm、チーム全体の導入ハードルの低さや既存エコシステムとの互換性を最優先するなら npm を選んでください。 モノレポ運用を本格的に行うプロジェクトでは pnpm のワークスペース機能が特に強力です。迷ったら、まず pnpm を小規模プロジェクトで試し、チームに合うか判断するのがおすすめです。


2. 比較表

観点pnpm (v9.x)npm (v10.x)
インストール速度⚡ 非常に高速(コンテンツアドレッサブルストア + ハードリンク)標準的(v10 で改善傾向)
ディスク使用量✅ グローバルストアで重複排除。大幅に節約❌ プロジェクトごとに node_modules をフルコピー
node_modules 構造厳密(非フラット/シンボリックリンク方式)フラット(hoisting)
幽霊依存 (Phantom Deps)✅ 構造的に防止❌ hoisting により発生しうる
モノレポ対応pnpm-workspace.yaml でネイティブ対応npm workspaces で対応(機能はやや限定的)
TypeScript 対応パッケージマネージャーなので直接関係なし(同等)同等
学習コストnpm とほぼ同じ CLI 体系。移行は容易Node.js 同梱。学習コストほぼゼロ
CI/CD 互換性主要 CI はすべて対応。corepack enable で導入可デフォルトで利用可能
Lock ファイルpnpm-lock.yamlpackage-lock.json
プラグイン / 拡張.pnpmfile.cjs でフック可能npm hookoverrides など
週間ダウンロード数 (2024)約 800 万Node.js 同梱のため計測対象外(事実上最多)
ライセンスMITArtistic-2.0

3. それぞれの強み

pnpm の強み

  • コンテンツアドレッサブルストア すべてのパッケージをグローバルストア (~/.local/share/pnpm/store) に一元管理し、各プロジェクトへはハードリンクで配置します。10 個のプロジェクトで同じバージョンの lodash を使っても、ディスク上の実体は 1 つだけです。

  • 厳密な依存関係ツリー package.json に宣言していないパッケージは require / import できません。これにより「開発環境では動くが本番でクラッシュする」幽霊依存問題を根本的に排除できます。

  • 高速なインストール ストアにキャッシュがある場合、ネットワークアクセスなしでインストールが完了します。大規模モノレポでは npm 比で 2〜3 倍の速度差 が出ることも珍しくありません。

  • ネイティブなモノレポサポート pnpm-workspace.yaml 1 ファイルで設定が完結し、--filter オプションで特定パッケージだけにコマンドを実行できます。

npm の強み

  • ゼロセットアップ Node.js をインストールした瞬間から使えます。チームメンバーへの追加ツール導入説明が不要です。

  • 圧倒的なエコシステム互換性 README やチュートリアルの大半が npm install で書かれており、コピー&ペーストでそのまま動きます。

  • 安定性と後方互換性 npm, Inc.(現 GitHub / Microsoft)が公式にメンテナンスしており、破壊的変更は慎重に管理されています。

  • npx の統合 CLI ツールの一時実行が npx でシームレスに行えます(pnpm にも pnpm dlx がありますが、認知度では npx が上回ります)。


4. コード例で比較

以下では「Express + TypeScript のプロジェクト初期化 → 依存追加 → スクリプト実行」を両方で行います。

npm の場合

# プロジェクト初期化
mkdir my-app && cd my-app
npm init -y

# 依存パッケージのインストール
npm install express
npm install -D typescript @types/express @types/node ts-node

# スクリプト実行
npx ts-node src/index.ts
// package.json(npm が生成)
{
  "name": "my-app",
  "version": "1.0.0",
  "scripts": {
    "dev": "npx ts-node src/index.ts"
  },
  "dependencies": {
    "express": "^4.21.0"
  },
  "devDependencies": {
    "typescript": "^5.6.0",
    "@types/express": "^5.0.0",
    "@types/node": "^22.0.0",
    "ts-node": "^10.9.0"
  }
}
// src/index.ts — 共通コード(どちらのマネージャーでも同じ)
import express, { Request, Response } from "express";

const app = express();
const PORT = 3000;

app.get("/", (_req: Request, res: Response) => {
  res.json({ message: "Hello from Express + TypeScript!" });
});

app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});

pnpm の場合

# pnpm の有効化(Node.js 16.13+ 同梱の corepack を利用)
corepack enable
corepack prepare pnpm@latest --activate

# プロジェクト初期化
mkdir my-app && cd my-app
pnpm init

# 依存パッケージのインストール
pnpm add express
pnpm add -D typescript @types/express @types/node ts-node

# スクリプト実行
pnpm dlx ts-node src/index.ts
# または package.json の scripts に書いて pnpm dev
// package.json(pnpm が生成 — npm とほぼ同一)
{
  "name": "my-app",
  "version": "1.0.0",
  "scripts": {
    "dev": "ts-node src/index.ts"
  },
  "dependencies": {
    "express": "^4.21.0"
  },
  "devDependencies": {
    "typescript": "^5.6.0",
    "@types/express": "^5.0.0",
    "@types/node": "^22.0.0",
    "ts-node": "^10.9.0"
  }
}

ポイント: package.json とアプリケーションコードはまったく同じです。違いはコマンド体系(npm installpnpm addnpxpnpm dlx)と、生成される node_modules の内部構造・ロックファイルだけです。

モノレポでの違い(ワークスペース設定)

# pnpm-workspace.yaml(pnpm)
packages:
  - "packages/*"
  - "apps/*"
# 特定パッケージだけにコマンド実行
pnpm --filter @my-org/api dev
pnpm --filter @my-org/web build
// package.json(npm workspaces)
{
  "workspaces": [
    "packages/*",
    "apps/*"
  ]
}
# 特定パッケージだけにコマンド実行
npm -w @my-org/api run dev
npm -w @my-org/web run build

5. どちらを選ぶべきか — ユースケース別推奨

ユースケース推奨理由
個人の小規模プロジェクトどちらでも OK差はほぼ体感できません
大規模モノレポ(10+ パッケージ)pnpm--filter の柔軟性、ディスク節約、インストール速度が顕著に効きます
CI/CD のビルド時間短縮が最優先pnpmキャッシュ効率が高く、コールドスタートでも高速です
OSS ライブラリの公開npm or pnpmコントリビューターの参入障壁を下げたいなら npm、厳密な依存管理を優先するなら pnpm
チームに Node.js 初心者が多いnpm追加ツール不要で学習リソースが豊富です
幽霊依存を絶対に許容したくないpnpm構造的に防止できる唯一の主要パッケージマネージャーです
Docker イメージサイズの最小化pnpmpnpm deploy でプロダクション依存だけを抽出でき、イメージの軽量化に貢献します
既存の npm プロジェクトからの移行pnpm (容易)pnpm importpackage-lock.json から pnpm-lock.yaml を自動生成できます

6. まとめ

npm は 「何も考えずにすぐ使える」安心感と互換性 が最大の武器です。Node.js エコシステムの事実上の標準であり、今後もその地位は揺るがないでしょう。

一方 pnpm は 「速度・ディスク効率・依存関係の正確さ」 という、プロジェクトが大きくなるほど効いてくる実利を提供します。CLI 体系が npm とほぼ同じため、移行コストは想像以上に低いです。

迷ったときの判断基準はシンプルです。

  • 今のプロジェクトで「node_modules が巨大すぎる」「CI が遅い」「宣言していないパッケージが import できてしまう」といった課題を感じているなら → pnpm を試してください。
  • 特に困っていないなら → npm のままで問題ありません。

どちらを選んでも package.json の書き方やアプリケーションコードは変わりません。パッケージマネージャーの切り替えはプロジェクトの寿命に比べれば小さな変更です。まずは手元で試し、チームに合う方を選びましょう。