Why pnpm?
pnpm is a fast, disk space efficient package manager that uses hard links and symbolic links to save disk space and improve installation speed. It's严格 deterministic and supports monorepos out of the box.
bash
# npm/yarn: Copies files to each project
node_modules/
├── lodash/ # Full copy
├── react/ # Full copy
└── express/ # Full copy
# pnpm: Uses hard links
node_modules/
├── lodash → ~/.pnpm-store/lodash@1.0.0
├── react → ~/.pnpm-store/react@18.0.0
└── express → ~/.pnpm-store/express@4.0.0Installation
Getting Started
bash
# Install pnpm globally
npm install -g pnpm
# Or using curl
curl -fsSL https://get.pnpm.io/install.sh | sh -
# Verify installation
pnpm --versionProject Setup
bash
# Create new project
pnpm init
# Install dependencies
pnpm install
# Add dependencies
pnpm add react
pnpm add -D typescript
# Install from package.json
pnpm installKey Features
Disk Efficiency
bash
# Check disk usage
du -sh node_modules/ # 500MB with npm/yarn
# With pnpm
du -sh node_modules/ # 50MB (10x smaller!)
# Store location
~/.pnpm-store/
# Check store size
du -sh ~/.pnpm-store/ # Same across all projectsSpeed
bash
# Installation speed comparison
npm install # 30s
yarn install # 25s
pnpm install # 10s (3x faster!)
# Because:
- Hard links instead of copying
- Parallel package downloads
- Efficient conflict resolutionStrict Dependencies
bash
# npm/yarn: Packages can access unlisted deps
node_modules/
├── package-a/
└── package-b/
└── node_modules/
└── lodash/ # Can access even if not listed!
# pnpm: Strict isolation
node_modules/
├── .pnpm/
│ ├── package-a@1.0.0/node_modules/package-a/
│ └── lodash@4.0.0/node_modules/lodash/
└── package-a → .pnpm/package-a@1.0.0/node_modules/package-a
# No access to unlisted dependenciesWorkspaces
Monorepo Setup
yaml
# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'Workspace Commands
bash
# Install all dependencies
pnpm install
# Add dependency to specific workspace
pnpm --filter web add react
# Add to all workspaces
pnpm -w add -D typescript
# Run script in specific workspace
pnpm --filter web dev
# Run in all workspaces
pnpm -r dev
pnpm -r buildWorkspace Dependencies
json
// packages/ui/package.json
{
"name": "@myorg/ui",
"dependencies": {
"@myorg/utils": "workspace:*"
}
}
// apps/web/package.json
{
"name": "@myorg/web",
"dependencies": {
"@myorg/ui": "workspace:*",
"@myorg/utils": "workspace:*"
}
}
// pnpm resolves workspace:* to actual versionAdvanced Usage
Filters
bash
# Filter by package name
pnpm --filter "@myorg/*" test
# Filter by directory
pnpm --filter "./packages/*" build
# Exclude packages
pnpm --filter "!@myorg/web" build
# Multiple filters
pnpm --filter @myorg/web --filter @myorg/api testScripts
json
// package.json
{
"scripts": {
"dev": "turbo run dev",
"build": "turbo run build",
"test": "turbo run test",
"lint": "turbo run lint",
"clean": "turbo run clean && rm -rf node_modules"
}
}Environment Variables
bash
# .npmrc
store-dir=~/.pnpm-store
shamefully-hoist=false
strict-peer-dependencies=false
# Environment variables
export pnpm_store_dir=$HOME/.pnpm-store
export pnpm_cache_dir=$HOME/.pnpm-cachePerformance Optimization
Cache Configuration
bash
# .npmrc
cache-dir=$HOME/.pnpm-cache
# Check cache stats
pnpm store status
# Prune cache
pnpm store prune
# Add to store
pnpm store addInstallation Options
bash
# Frozen lockfile for CI
pnpm install --frozen-lockfile
# Prefer offline mode
pnpm install --prefer-offline
# Ignore scripts
pnpm install --ignore-scripts
# Force reinstall
pnpm install --forceCommon Commands
Dependency Management
bash
# Add dependencies
pnpm add react
pnpm add -D typescript
pnpm add -O lodash # optional dependency
# Remove dependencies
pnpm remove react
# Update dependencies
pnpm update
pnpm update react
pnpm update --latest
# Outdated packages
pnpm outdatedInformation Commands
bash
# List installed packages
pnpm list
pnpm list --depth=0
pnpm list --prod
# Show package info
pnpm info react
pnpm why react
# Check licenses
pnpm licenses list
pnpm licenses verifyCI/CD Integration
GitHub Actions
yaml
name: CI
on: [push, pull_request]
jobs:
install-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v3
with:
node-version: 18
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run tests
run: pnpm test
- name: Build
run: pnpm buildDocker
dockerfile
FROM node:18-alpine
# Install pnpm
RUN npm install -g pnpm
# Copy package files
COPY package.json pnpm-lock.yaml ./
# Install dependencies
RUN pnpm install --frozen-lockfile
# Copy source
COPY . .
# Build
RUN pnpm build
CMD ["pnpm", "start"]Best Practices
1. Use Strict Peer Dependencies
bash
# .npmrc
strict-peer-dependencies=true
# Catch peer dependency conflicts
# Prevent runtime errors2. Enable Auto-Install Peers
bash
# .npmrc
auto-install-peers=true
# Automatically install peer dependencies
# Simpler dependency management3. Use .npmrc for Team Consistency
bash
# .npmrc (commit to repo)
auto-install-peers=true
strict-peer-dependencies=false
shamefully-hoist=false
# Ensures consistent installs across team4. Lock File Management
bash
# Commit pnpm-lock.yaml
git add pnpm-lock.yaml
# Use --frozen-lockfile in CI
pnpm install --frozen-lockfile
# Update lockfile carefully
pnpm update # Updates lockfile
git commit -m "Update dependencies"Troubleshooting
Permission Issues
bash
# Problem: EACCES permission errors
pnpm install
# Solution: Fix store permissions
sudo chown -R $(whoami) ~/.pnpm-store
# Or use different store directory
pnpm config set store-dir ~/pnpm-storeDependency Conflicts
bash
# Problem: Peer dependency conflicts
pnpm install
# Solution: Use overrides
{
"pnpm": {
"overrides": {
"react": "18.2.0"
}
}
}Store Corruption
bash
# Problem: Store corrupted
pnpm install
# error: ENOENT
# Solution: Rebuild store
rm -rf ~/.pnpm-store
pnpm installMigration from npm/yarn
Easy Migration
bash
# From npm/yarn
rm -rf node_modules package-lock.json
pnpm install
# That's it! pnpm reads package.json
# Generates pnpm-lock.yamlScripts Compatibility
json
// All npm scripts work with pnpm
{
"scripts": {
"start": "node server.js",
"build": "webpack --mode production",
"test": "jest"
}
}
// Run with pnpm
pnpm start
pnpm run build
pnpm testPerformance Comparison
Benchmarks
bash
# Installation speed (1000 packages)
npm: 30s
yarn: 25s
pnpm: 10s
# Disk usage (10 projects)
npm: 5GB
yarn: 5GB
pnpm: 500MB (10x less!)
# Maximum node_modules depth
npm: Unlimited (can nest forever)
yarn: Unlimited
pnpm: 2 (max!)Conclusion
pnpm offers superior speed, disk efficiency, and strict dependency management. With built-in workspace support, it's perfect for monorepos and modern JavaScript projects.
Key takeaways:
- Faster than npm/yarn
- Uses 10x less disk space
- Strict dependency isolation
- Excellent workspace support
- Easy migration from npm/yarn
Switch to pnpm for faster, more efficient package management!