Skip to content
All essays
CraftMarch 27, 202511 min

pnpm: Fast, Disk-Efficient Package Manager

Master pnpm package manager. Learn about its speed, disk efficiency, workspace support, and monorepo capabilities.

Ü
Ümit Uz
Mobile & Full Stack Developer

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.0

Installation

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 --version

Project 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 install

Key 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 projects

Speed

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 resolution

Strict 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 dependencies

Workspaces

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 build

Workspace 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 version

Advanced 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 test

Scripts

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-cache

Performance 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 add

Installation 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 --force

Common 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 outdated

Information 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 verify

CI/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 build

Docker

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 errors

2. Enable Auto-Install Peers

bash
# .npmrc
auto-install-peers=true

# Automatically install peer dependencies
# Simpler dependency management

3. 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 team

4. 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-store

Dependency 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 install

Migration 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.yaml

Scripts 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 test

Performance 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!

Enjoyed this essay? Share it.

Related essays

Next essay
User Behavior Analytics: Understand Your Users