pnpm完全ガイド2026 - 高速パッケージマネージャー、コンテンツアドレッサブルストレージ、ワークスペース、npm互換
pnpm完全ガイド2026
pnpmは、高速でディスクスペース効率が良いパッケージマネージャーです。本記事では、基本から応用までを網羅的に解説します。
目次
- pnpmとは
- インストールとセットアップ
- 基本的なコマンド
- コンテンツアドレッサブルストレージ
- 厳格な依存関係管理
- ワークスペース
- npm/yarnからの移行
- モノレポ構築
- パフォーマンス最適化
pnpmとは
特徴と強み
/**
* pnpm の特徴
*
* 1. 高速インストール
* - ハードリンクによる高速コピー
* - 並列インストール
* - キャッシュ効率
*
* 2. ディスクスペース効率
* - グローバルストアで一元管理
* - 同じパッケージを1回だけ保存
* - ハードリンクで参照
*
* 3. 厳格な依存関係
* - Phantom dependencies 防止
* - 宣言した依存のみアクセス可能
*
* 4. npm互換
* - package.json そのまま使用
* - npm scripts 互換
* - 既存プロジェクトに簡単導入
*/
// パッケージマネージャー比較
const comparison = {
npm: {
speed: '普通',
diskSpace: '大きい(node_modules が独立)',
strictness: '緩い',
},
yarn: {
speed: '速い',
diskSpace: '大きい(node_modules が独立)',
strictness: '緩い',
},
pnpm: {
speed: '最速',
diskSpace: '最小(グローバルストアで共有)',
strictness: '厳格',
},
}
アーキテクチャ
# pnpm のストレージ構造
~/.pnpm-store/ # グローバルストア
└── v3/
└── files/
└── 00/ # content-addressable
└── abcd123... # パッケージの実体
# プロジェクト内
node_modules/
├── .pnpm/ # 仮想ストア
│ ├── react@18.2.0/
│ │ └── node_modules/
│ │ └── react/ # ハードリンク
│ └── lodash@4.17.21/
└── react -> .pnpm/react@18.2.0/node_modules/react # シンボリックリンク
インストールとセットアップ
pnpmのインストール
# npm でインストール
npm install -g pnpm
# Homebrew(macOS)
brew install pnpm
# スタンドアロンスクリプト
curl -fsSL https://get.pnpm.io/install.sh | sh -
# バージョン確認
pnpm --version
グローバル設定
# ストアの場所を確認
pnpm store path
# ストアの場所を変更
pnpm config set store-dir /path/to/store
# ストアのサイズを確認
pnpm store status
# 未使用パッケージを削除
pnpm store prune
# 設定一覧
pnpm config list
プロジェクト初期化
# 新規プロジェクト
pnpm init
# package.json 作成(詳細)
pnpm init -y
# TypeScript プロジェクト
pnpm create vite my-app --template react-ts
cd my-app
pnpm install
基本的なコマンド
パッケージ管理
# インストール
pnpm install # または pnpm i
pnpm install react # パッケージ追加
pnpm add react # 同上(エイリアス)
# 開発依存
pnpm add -D typescript
pnpm add --save-dev @types/node
# グローバルインストール
pnpm add -g typescript
# 特定バージョン
pnpm add react@18.2.0
pnpm add react@latest
pnpm add react@next
# 複数同時
pnpm add react react-dom
# アンインストール
pnpm remove react # または pnpm rm, pnpm uninstall
pnpm remove -g typescript
# アップデート
pnpm update # すべて更新
pnpm update react # 特定パッケージ
pnpm update --latest # 最新に更新(semverを無視)
pnpm update -i # インタラクティブ更新
パッケージ情報
# インストール済みパッケージ一覧
pnpm list # または pnpm ls
pnpm list --depth 0 # トップレベルのみ
pnpm list --depth 1 # 1階層まで
pnpm list react # 特定パッケージ
# グローバルパッケージ
pnpm list -g
# 依存関係ツリー
pnpm why react # なぜこのパッケージが必要か
# 最新バージョン確認
pnpm outdated
pnpm outdated --depth 0
スクリプト実行
# npm scripts 実行
pnpm run dev # または pnpm dev
pnpm run build
pnpm run test
# スクリプト一覧
pnpm run
# 複数プロジェクトで実行(ワークスペース)
pnpm -r run build # すべてで build
pnpm --filter web run dev # 特定プロジェクトで dev
コンテンツアドレッサブルストレージ
仕組みの理解
/**
* Content-Addressable Storage
*
* 1. ファイルハッシュで管理
* - SHA-512 でファイル内容をハッシュ化
* - 同じファイルは1つだけ保存
*
* 2. ハードリンク
* - グローバルストアから参照
* - ディスクスペース節約
* - コピー不要で高速
*
* 3. 整合性チェック
* - ファイル改ざん検知
* - 自動修復
*/
// 実際のストレージ構造
interface PnpmStore {
version: string
files: {
[hash: string]: {
path: string
integrity: string
size: number
}
}
}
ストレージ管理
# ストア統計
pnpm store status
# ✔ Store path: /Users/user/.pnpm-store/v3
# ✔ Size: 2.5 GB
# ✔ Packages: 15432
# 未使用パッケージ削除
pnpm store prune
# ストア完全再構築
rm -rf ~/.pnpm-store
pnpm install --force
# ストレージパス変更(プロジェクト固有)
echo "store-dir=./.pnpm-store" > .npmrc
パフォーマンスベンチマーク
// インストール速度比較(実測例)
const installBenchmark = {
npm: {
cold: '45s', // キャッシュなし
warm: '12s', // キャッシュあり
},
yarn: {
cold: '35s',
warm: '8s',
},
pnpm: {
cold: '25s',
warm: '3s', // 最速
},
}
// ディスクスペース比較
const diskUsage = {
npm: '1.2 GB', // プロジェクトごと
yarn: '1.1 GB',
pnpm: '150 MB', // ハードリンクで共有
}
厳格な依存関係管理
Phantom Dependencies防止
// package.json
{
"dependencies": {
"react": "^18.2.0"
// lodash は直接依存していない
}
}
// ❌ npm/yarn では動作してしまう(Phantom dependency)
import _ from 'lodash' // react の依存として間接的にインストールされている
// ✅ pnpm では エラー
// Error: Cannot find module 'lodash'
// → 明示的に追加する必要がある
厳格モードの設定
# .npmrc
# 厳格な依存関係チェック(デフォルト)
strict-peer-dependencies=true
# Hoisting を無効化(推奨)
shamefully-hoist=false
public-hoist-pattern[]=
# lockfile のみ使用(package.json 無視)
frozen-lockfile=true
ピア依存関係の管理
// package.json
{
"peerDependencies": {
"react": "^18.0.0"
},
"peerDependenciesMeta": {
"react": {
"optional": true // オプショナルピア依存
}
}
}
# ピア依存関係の自動インストール
pnpm install --strict-peer-dependencies
# ピア依存関係の警告を無視
pnpm install --no-strict-peer-dependencies
ワークスペース
ワークスペース設定
# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
- '!**/test/**'
// package.json(ルート)
{
"name": "monorepo",
"private": true,
"scripts": {
"dev": "pnpm -r --parallel run dev",
"build": "pnpm -r run build",
"test": "pnpm -r run test"
}
}
ワークスペースプロトコル
// packages/web/package.json
{
"name": "@myorg/web",
"dependencies": {
"@myorg/ui": "workspace:*", // 最新バージョン
"@myorg/utils": "workspace:^1.0.0", // semver範囲
"@myorg/api": "workspace:~" // 同じマイナーバージョン
}
}
フィルターコマンド
# 特定パッケージで実行
pnpm --filter @myorg/web run dev
pnpm --filter "./packages/ui" run build
# 複数パッケージ
pnpm --filter "@myorg/*" run test
pnpm --filter "web..." run build # web とその依存
# 依存グラフを考慮
pnpm --filter ...web run build # web が依存するすべて
pnpm --filter "web^..." run build # web を依存するすべて
# 並列実行
pnpm -r --parallel run dev
# 順次実行(依存順)
pnpm -r run build
# 変更されたパッケージのみ
pnpm --filter "[main]" run test # main ブランチからの変更
ワークスペース間の依存
// packages/ui/package.json
{
"name": "@myorg/ui",
"version": "1.0.0",
"main": "./dist/index.js",
"exports": {
".": "./dist/index.js",
"./button": "./dist/button.js"
}
}
// packages/web/src/App.tsx
import { Button } from '@myorg/ui/button'
function App() {
return <Button>Click me</Button>
}
npm/yarnからの移行
移行手順
# 1. pnpm インストール
npm install -g pnpm
# 2. 既存の node_modules 削除
rm -rf node_modules
# 3. pnpm でインストール
pnpm install
# 4. lockfile 移行(オプション)
pnpm import # package-lock.json または yarn.lock から変換
# 5. npm/yarn scripts はそのまま動作
pnpm run dev
pnpm test
互換性設定
# .npmrc
# npm と同じ挙動にする(非推奨)
shamefully-hoist=true
# yarn の Plug'n'Play と似た挙動
node-linker=pnp
# デフォルト(推奨)
node-linker=isolated
CI/CD設定
# GitHub Actions
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# pnpm セットアップ
- uses: pnpm/action-setup@v2
with:
version: 8
# Node.js セットアップ
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
# インストール
- run: pnpm install --frozen-lockfile
# ビルド・テスト
- run: pnpm run build
- run: pnpm test
# Dockerfile
FROM node:20-alpine
# pnpm インストール
RUN npm install -g pnpm
WORKDIR /app
# 依存関係のみコピー(キャッシュ効率化)
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --prod
# ソースコードコピー
COPY . .
CMD ["pnpm", "start"]
モノレポ構築
完全なモノレポ構成
my-monorepo/
├── pnpm-workspace.yaml
├── package.json
├── .npmrc
├── apps/
│ ├── web/ # Next.js アプリ
│ │ ├── package.json
│ │ └── src/
│ └── api/ # Express API
│ ├── package.json
│ └── src/
├── packages/
│ ├── ui/ # UI コンポーネント
│ │ ├── package.json
│ │ └── src/
│ ├── utils/ # ユーティリティ
│ │ ├── package.json
│ │ └── src/
│ └── config/ # 共通設定
│ ├── eslint-config/
│ └── tsconfig/
└── tooling/
└── scripts/
共通設定の共有
// packages/config/tsconfig/base.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true
}
}
// apps/web/tsconfig.json
{
"extends": "@myorg/tsconfig/base.json",
"compilerOptions": {
"jsx": "preserve",
"lib": ["DOM", "DOM.Iterable", "ES2022"]
}
}
// packages/config/eslint-config/index.js
module.exports = {
extends: ['next', 'prettier'],
rules: {
'no-console': 'warn',
},
}
// apps/web/.eslintrc.js
module.exports = {
extends: ['@myorg/eslint-config'],
}
ビルドパイプライン
// package.json(ルート)
{
"scripts": {
// 並列ビルド
"build": "pnpm -r run build",
// 依存順ビルド
"build:deps": "pnpm -r --workspace-concurrency=1 run build",
// 特定アプリとその依存のみ
"build:web": "pnpm --filter ...@myorg/web run build",
// 開発モード(並列)
"dev": "pnpm -r --parallel run dev",
// テスト
"test": "pnpm -r run test",
"test:changed": "pnpm --filter \"[origin/main]\" run test",
// Lint
"lint": "pnpm -r run lint",
"lint:fix": "pnpm -r run lint -- --fix"
}
}
カタログ機能(pnpm 9.0+)
# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
catalog:
react: ^18.2.0
typescript: ^5.3.0
'@types/node': ^20.0.0
eslint: ^8.56.0
// packages/ui/package.json
{
"dependencies": {
"react": "catalog:" // カタログから取得
},
"devDependencies": {
"typescript": "catalog:",
"@types/node": "catalog:"
}
}
パフォーマンス最適化
キャッシュ戦略
# .npmrc
# ネットワークキャッシュ
fetch-retries=3
fetch-retry-mintimeout=10000
# ストアキャッシュ
package-import-method=auto # ハードリンク自動選択
# ロックファイル設定
lockfile=true
prefer-frozen-lockfile=true
# 並列処理
network-concurrency=16
CI最適化
# .github/workflows/ci.yml
- name: Get pnpm store directory
id: pnpm-cache
run: echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
部分インストール
# 本番依存のみ
pnpm install --prod
# 開発依存のみ
pnpm install --dev
# オプショナル依存をスキップ
pnpm install --no-optional
# ワークスペースの特定パッケージのみ
pnpm --filter @myorg/web install
まとめ
pnpmは、高速でディスクスペース効率が良く、厳格な依存関係管理を実現するパッケージマネージャーです。
主要ポイント:
- コンテンツアドレッサブルストレージ: ディスクスペース大幅削減
- 厳格な依存関係: Phantom dependencies を防止
- ワークスペース: モノレポに最適
- npm互換: 既存プロジェクトに簡単導入
- 高速: npm/yarnより高速なインストール
2026年のベストプラクティス:
- 新規プロジェクトは pnpm を採用
- モノレポ構築に pnpm workspace
- CI/CD でキャッシュ活用
- カタログ機能で依存バージョン統一
- 厳格モードで品質向上
pnpmを活用して、効率的で堅牢な開発環境を構築しましょう。