
Pnpm
- 1.7k installs
- 696 repo stars
- Updated July 27, 2026
- onmax/nuxt-skills
pnpm workspace and catalog guide.
About
The pnpm skill covers content-addressable store strict deps workspace protocol and catalogs for Node monorepos. Quick start install add dev deps recursive run and filter commands. Workspace setup via pnpm-workspace.yaml with catalog centralized versions and workspace protocol dependencies. Use installing packages monorepo setup catalog version management overriding transitive deps patching third-party packages and CI hardening for pnpm projects with supply chain security focus. Content-addressable store strict dependencies. pnpm-workspace.yaml and catalogs. workspace protocol and filter runs. Overrides patches CI configuration. Supply chain security hardening. pnpm workspace and catalog guide. User asks pnpm workspace catalog override.
- Content-addressable store strict dependencies.
- pnpm-workspace.yaml and catalogs.
- workspace protocol and filter runs.
- Overrides patches CI configuration.
- Supply chain security hardening.
Pnpm by the numbers
- 1,654 all-time installs (skills.sh)
- +30 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #129 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
pnpm capabilities & compatibility
- Capabilities
- workspace setup · catalog versions
- Use cases
- ci cd · devops
npx skills add https://github.com/onmax/nuxt-skills --skill pnpmAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.7k |
|---|---|
| repo stars | ★ 696 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 27, 2026 |
| Repository | onmax/nuxt-skills ↗ |
Setup pnpm monorepo catalogs?
Manage pnpm workspaces catalogs overrides patches and CI for Node monorepos with strict dependency rules.
Who is it for?
Node monorepo maintainers.
Skip if: yarn-only legacy.
When should I use this skill?
User asks pnpm workspace catalog override.
What you get
pnpm workspace with overrides and CI.
- GitHub Actions CI workflow YAML
- pnpm store cache configuration
By the numbers
- Uses pnpm version 9 and Node.js 20 in GitHub Actions examples
Files
pnpm
Content-addressable store, strict deps, workspace protocol, catalogs.
When to Use
- Installing/managing npm packages
- Monorepo workspace setup with catalogs
- Overriding transitive dependencies
- Patching third-party packages
- CI/CD configuration for pnpm projects
- Supply chain security hardening
Quick Start
pnpm install # Install deps
pnpm add <pkg> # Add dep
pnpm add -D <pkg> # Dev dep
pnpm -r run build # Run in all packages
pnpm --filter @myorg/app build # Run in specific packageWorkspace Setup
# pnpm-workspace.yaml
packages:
- 'packages/*'
- 'apps/*'
# Catalogs for centralized version management
catalog:
react: ^18.2.0
typescript: ~5.3.0// package.json - Use workspace protocol and catalogs
{
"packageManager": "pnpm@10.28.2",
"dependencies": {
"@myorg/utils": "workspace:^",
"react": "catalog:"
}
}Reference Files
| Task | File |
|---|---|
| Commands, scripts, filtering | cli.md |
| Workspaces, catalogs, config | workspaces.md |
| Overrides, patches, hooks, store | features.md |
| CI/CD, Docker, migration | ci.md |
Loading Files
Consider loading these reference files based on your task:
- [ ] references/cli.md - if using pnpm commands, scripts, or filtering
- [ ] references/workspaces.md - if setting up monorepo, catalogs, or workspace config
- [ ] references/features.md - if using overrides, patches, hooks, or managing store
- [ ] references/ci.md - if configuring CI/CD, Docker, or migrating from npm/yarn
DO NOT load all files at once. Load only what's relevant to your current task.
Verify Setup
After configuring a workspace, verify it works:
pnpm install # Install all deps
pnpm ls --depth 0 # Verify workspace links
pnpm -r run build # Build all packagesCross-Skill References
- TypeScript libs → Use
ts-libraryskill for library patterns - Build tooling → Use
tsdownorviteskills
CI/CD & Migration
GitHub Actions
Basic Setup
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- run: pnpm test
- run: pnpm buildWith Store Caching
- uses: pnpm/action-setup@v4
with:
version: 9
- name: Get pnpm store directory
shell: bash
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- run: pnpm install --frozen-lockfileMonorepo - Build Changed Only
- name: Build changed packages
run: pnpm --filter "...[origin/main]" buildGitLab CI
image: node:20
variables:
PNPM_HOME: /root/.local/share/pnpm
PATH: $PNPM_HOME:$PATH
before_script:
- corepack enable
- corepack prepare pnpm@latest --activate
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .pnpm-store
install:
script:
- pnpm config set store-dir .pnpm-store
- pnpm install --frozen-lockfileDocker
Multi-Stage Build
FROM node:20-slim AS builder
RUN corepack enable
WORKDIR /app
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY packages/*/package.json ./packages/
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
FROM node:20-slim AS runner
RUN corepack enable
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./
COPY --from=builder /app/pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --prod
CMD ["node", "dist/index.js"]Key CI Flags
--frozen-lockfile # Always use in CI
--prefer-offline # Use cached packages
--ignore-scripts # Faster (careful: some deps need scripts)Corepack
// package.json - Specify exact pnpm version
{
"packageManager": "pnpm@10.28.2"
}# CI
- run: corepack enable
- run: pnpm install --frozen-lockfileNote: pnpm 11+ ships with its own Node.js version and doesn't rely on system installation.
Migration from npm
rm -rf node_modules package-lock.json
pnpm installMigration from Yarn
rm -rf node_modules yarn.lock
rm -rf .yarn .yarnrc.yml # Yarn Berry
pnpm installImport Lockfile
pnpm import # Creates pnpm-lock.yaml from existing lockfileHandling Phantom Dependencies
pnpm is strict - imports must be in package.json:
# Error: lodash not found (it's a transitive dep)
# Solution: add it explicitly
pnpm add lodashSymlink Issues
Some tools don't work with symlinks:
# .npmrc - Use npm-like flat structure
node-linker=hoistedOr hoist specific packages:
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*babel*Monorepo Migration
1. Create pnpm-workspace.yaml:
packages:
- 'packages/*'2. Update internal deps to workspace protocol:
{ "@myorg/utils": "workspace:^" }3. Install:
rm -rf node_modules packages/*/node_modules
pnpm installPerformance Tips
# .npmrc
prefer-offline=true
side-effects-cache=true
workspace-concurrency=4
onlyBuiltDependencies[]=esbuild
onlyBuiltDependencies[]=@swc/core# Build changed only
pnpm --filter "...[origin/main]" build
# Parallel workspace
pnpm -r --parallel run test
# Clean store (v10.27+ includes global virtual store)
pnpm store pruneSecurity Best Practices
# CI - prevent script execution
pnpm install --frozen-lockfile --ignore-scripts
# Use exact lockfile (prevents supply chain attacks)
pnpm install --frozen-lockfile
# Audit dependencies
pnpm auditScripts Migration
{
"scripts": {
// npm workspaces
"build:all": "npm run build --workspaces",
// pnpm
"build:all": "pnpm -r run build",
// npm specific workspace
"dev:app": "npm run dev -w packages/app",
// pnpm
"dev:app": "pnpm --filter @myorg/app run dev"
}
}CLI Commands
Installation
pnpm install # Install all deps
pnpm i # Alias
pnpm install --frozen-lockfile # CI mode - fail if lockfile outdated
pnpm install --prefer-offline # Use cache when available
pnpm install --offline # Use store only (no network)
pnpm install --prod # Production only
pnpm install --no-optional # Skip optional deps
pnpm install --ignore-scripts # Skip lifecycle scripts
# Platform overrides (v10.14+)
pnpm install --cpu=arm64 # Override CPU architecture
pnpm install --os=darwin # Override OS
pnpm install --libc=musl # Override libc for native modulesAdding Dependencies
pnpm add <pkg> # Production dep
pnpm add -D <pkg> # Dev dep
pnpm add -O <pkg> # Optional dep
pnpm add -g <pkg> # Global
pnpm add <pkg>@<version> # Specific version
pnpm add <pkg>@next # Tag
pnpm add <pkg>@^1.0.0 # RangeRemoving Dependencies
pnpm remove <pkg>
pnpm rm <pkg>
pnpm uninstall <pkg>
pnpm un <pkg>Updating Dependencies
pnpm update # Update all
pnpm up <pkg> # Update specific
pnpm up --latest # Ignore semver
pnpm up -L # Alias
pnpm up --interactive # Interactive mode
pnpm up -i # AliasRunning Scripts
pnpm run <script> # Run script
pnpm <script> # Shorthand
pnpm run build -- --watch # Pass args
pnpm run --if-present build # No error if missingExecuting Binaries
pnpm exec <cmd> # Run local binary
pnpm exec eslint . # Example
pnpm dlx <pkg> # Like npx, no install
pnpm dlx create-vite my-appWorkspace Commands
pnpm -r run <script> # Run in all packages
pnpm --recursive run <script>
pnpm -r --parallel run build # Parallel
pnpm -r --stream run dev # Stream output
pnpm -r --workspace-concurrency=1 run build # SequentialFiltering
# By package name
pnpm --filter <name> <cmd>
pnpm -F <name> <cmd>
pnpm --filter "@scope/pkg" build
# By directory
pnpm --filter "./packages/core" test
# Glob patterns
pnpm --filter "@myorg/*" lint
pnpm --filter "!@myorg/internal-*" publish
# Dependencies of package
pnpm --filter "...@scope/app" build
# Dependents of package
pnpm --filter "@scope/core..." test
# Changed since git ref
pnpm --filter "...[origin/main]" build
pnpm --filter "[HEAD~5]" lintLink Packages
pnpm link --global # Make global
pnpm link -g
pnpm link --global <pkg> # Use linked packagePatching
pnpm patch <pkg>@<version> # Create temp dir for editing
pnpm patch-commit <path> # Save patch
pnpm patch-remove <pkg> # Remove patchStore Management
pnpm store path # Show location
pnpm store prune # Remove unused
pnpm store status # Check integrity
pnpm store add <pkg> # Add without installingInformation Commands
pnpm list # List installed
pnpm ls --depth=0 # Top-level only
pnpm ls --json # JSON output
pnpm why <pkg> # Why installed
pnpm outdated # Show outdated
pnpm audit # Security checkOther Commands
pnpm import # Import from npm/yarn lockfile
pnpm rebuild # Rebuild native modules
pnpm pack # Create tarball
pnpm publish # Publish to registry
pnpm publish -r --no-git-checks # CI publishEnvironment
# Using Corepack (recommended)
corepack enable
corepack prepare pnpm@latest --activate
# package.json - Specify pnpm version
{
"packageManager": "pnpm@10.28.2"
}Version Notes
- pnpm 10.x - Current stable (recommended)
- pnpm 11.x - Alpha release with breaking changes (pure ESM, new config format)
- Node.js v18/v19 support dropped
.npmrcproject configs →packageConfigsinpnpm-workspace.yaml- New build permission system
Features
Overrides
Force specific versions of dependencies:
# pnpm-workspace.yaml (recommended)
overrides:
lodash: ^4.17.21
'foo@^1.0.0': ^1.2.3 # Specific parent version
'express>cookie': ^0.6.0 # Nested dep
'underscore': 'npm:lodash@^4' # Replace package
'unwanted-pkg': '-' # Remove entirelyOr in package.json:
{
"pnpm": {
"overrides": {
"lodash": "^4.17.21"
}
}
}Patches
Modify third-party packages:
# 1. Start patch
pnpm patch express@4.18.2
# Output: /tmp/abc123...
# 2. Edit files in temp dir
cd /tmp/abc123...
# Make changes
# 3. Commit patch
pnpm patch-commit /tmp/abc123...Creates patches/express@4.18.2.patch and updates package.json:
{
"pnpm": {
"patchedDependencies": {
"express@4.18.2": "patches/express@4.18.2.patch"
}
}
}pnpm patch-remove express@4.18.2 # Remove patchAliases
Install packages under different names:
{
"dependencies": {
"lodash3": "npm:lodash@3",
"lodash4": "npm:lodash@4"
}
}import lodash3 from 'lodash3'
import lodash4 from 'lodash4'Replace packages:
{
"dependencies": {
"request": "npm:@cypress/request@^3.0.0"
}
}Hooks (.pnpmfile.cjs)
// .pnpmfile.cjs
function readPackage(pkg, context) {
// Add missing peer dep
if (pkg.name === 'broken-package') {
pkg.peerDependencies = {
...pkg.peerDependencies,
react: '*',
}
}
// Override version
if (pkg.dependencies?.lodash) {
pkg.dependencies.lodash = '^4.17.21'
}
// Remove unwanted dep
delete pkg.optionalDependencies?.fsevents
return pkg
}
function afterAllResolved(lockfile, context) {
context.log(`Resolved ${Object.keys(lockfile.packages || {}).length} packages`)
return lockfile
}
function beforePacking(pkg, context) {
// Customize package.json before publishing (v10.28+)
pkg.main = './dist/index.js'
return pkg
}
module.exports = {
hooks: {
readPackage,
afterAllResolved,
beforePacking, // v10.28+
},
}Peer Dependencies
# .npmrc
auto-install-peers=true # Default in pnpm v8+
strict-peer-dependencies=false # Don't fail on issuesSuppress warnings:
{
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": ["@babel/*", "eslint"],
"allowedVersions": {
"react": "17 || 18",
"@types/react": "*"
},
"allowAny": ["@types/*"]
}
}
}Store
Content-addressable storage - packages stored once globally, hard-linked to projects.
~/.pnpm-store/ # Global store
└── v3/files/<hash>/
project/node_modules/
├── .pnpm/ # Virtual store (hard links)
│ ├── lodash@4.17.21/
│ └── express@4.18.2/
├── lodash -> .pnpm/lodash@4.17.21/...
└── express -> .pnpm/express@4.18.2/...Node Linker Modes
# Default - strict, no phantom deps
node-linker=isolated
# npm-like flat structure
node-linker=hoisted
# Yarn PnP mode
node-linker=pnpStore Commands
pnpm store path
pnpm store prune
pnpm store statusTroubleshooting
# For Docker/network drives
package-import-method=copySide Effects Cache
Cache native module builds:
side-effects-cache=trueSecurity
Build Controls
# Only build specific deps
onlyBuiltDependencies[]=esbuild
onlyBuiltDependencies[]=sharp
# Skip all scripts
ignore-scripts=true
# Strict build deps (default in pnpm 11+)
strict-dep-builds=true{
"pnpm": {
"neverBuiltDependencies": ["fsevents", "cpu-features"]
}
}Supply Chain Protection
pnpm 10.x+ includes security hardening:
- Path traversal protection - Validates symlinks in
file:andgit:dependencies - Tarball validation - Prevents malicious extraction on Windows
- Bin linking protection - Validates
directories.binfield
# Prevent postinstall scripts from running (reduces attack surface)
pnpm install --ignore-scripts
# Use lockfile strictly (ensures reproducible builds)
pnpm install --frozen-lockfileWorkspaces & Configuration
pnpm-workspace.yaml
packages:
- 'packages/*'
- 'apps/*'
- 'tools/*/packages/*'
- '!**/test/**' # Exclude
# Catalogs for shared versions
catalog:
react: ^18.2.0
typescript: ~5.3.0
vite: ^5.0.0
catalogs:
react17:
react: ^17.0.2
react-dom: ^17.0.2
react18:
react: ^18.2.0
react-dom: ^18.2.0
# Overrides
overrides:
lodash: ^4.17.21
'foo@^1.0.0>bar': ^2.0.0
# Settings (alternative to .npmrc)
settings:
auto-install-peers: true
strict-peer-dependencies: false
link-workspace-packages: trueWorkspace Protocol
Reference local packages:
{
"dependencies": {
"@myorg/utils": "workspace:*",
"@myorg/core": "workspace:^",
"@myorg/types": "workspace:~"
}
}| Protocol | Behavior | Published As |
|---|---|---|
workspace:* | Any version | 1.2.3 |
workspace:^ | Compatible | ^1.2.3 |
workspace:~ | Patch | ~1.2.3 |
workspace:^1.0.0 | Range | ^1.0.0 |
Catalogs
Centralized version management - define dependency versions once, reference everywhere.
# pnpm-workspace.yaml
catalog:
lodash: ^4.17.21
zod: ^3.22.0// package.json
{
"dependencies": {
"lodash": "catalog:",
"zod": "catalog:"
}
}Named catalogs:
{
"dependencies": {
"react": "catalog:react18"
}
}Catalog Settings
# .npmrc
catalog-mode=manual # Default - don't auto-add to catalog
catalog-mode=strict # Fail if dep not in catalog
catalog-mode=prefer # Use catalog version if exists, otherwise regular
cleanup-unused-catalogs=true # Remove unused entries on install (v10.15+)On publish, catalog: becomes actual version.
Benefits
- Unique versions - Prevent version conflicts across workspace
- Easy upgrades - Update one place instead of many package.json files
- Fewer merge conflicts - Changes localized to workspace file
.npmrc Settings
# Peer deps
auto-install-peers=true
strict-peer-dependencies=false
# Hoisting
public-hoist-pattern[]=*types*
public-hoist-pattern[]=*eslint*
shamefully-hoist=false
# Store
store-dir=~/.pnpm-store
virtual-store-dir=node_modules/.pnpm
# Lockfile
lockfile=true
prefer-frozen-lockfile=true
# Performance
side-effects-cache=true
# Registry
registry=https://registry.npmjs.org/
@myorg:registry=https://npm.myorg.com/
# Workspace
link-workspace-packages=true
prefer-workspace-packages=true
shared-workspace-lockfile=true
save-workspace-protocol=rolling
inject-workspace-packages=false # Hard-link instead of symlink
# Node.js (use devEngines.runtime in pnpm 11+)
use-node-version=20.10.0
node-version-file=.nvmrcpackage.json pnpm Field
{
"pnpm": {
"overrides": {
"lodash": "^4.17.21"
},
"peerDependencyRules": {
"ignoreMissing": ["@babel/*"],
"allowedVersions": { "react": "17 || 18" },
"allowAny": ["@types/*"]
},
"neverBuiltDependencies": ["fsevents"],
"onlyBuiltDependencies": ["esbuild"],
"patchedDependencies": {
"express@4.18.2": "patches/express@4.18.2.patch"
},
"syncInjectedDepsAfterScripts": ["build"] // v10.5+ - sync hardlinked deps after scripts
}
}Configuration Hierarchy
1. /etc/npmrc - Global 2. ~/.npmrc - User 3. <project>/.npmrc - Project 4. npm_config_<key>=<value> - Environment 5. pnpm-workspace.yaml settings
Project Structure
my-monorepo/
├── pnpm-workspace.yaml
├── package.json
├── pnpm-lock.yaml
├── .npmrc
├── packages/
│ ├── core/
│ │ └── package.json
│ ├── utils/
│ │ └── package.json
│ └── types/
│ └── package.json
└── apps/
├── web/
│ └── package.json
└── api/
└── package.jsonWorkspace Scripts
# Install specific package dep
pnpm --filter @myorg/app add lodash
# Add workspace dep
pnpm --filter @myorg/app add @myorg/utils
# Run in topological order
pnpm -r run build
# Run in parallel
pnpm -r --parallel run test
# Execute in all packages
pnpm -r exec rm -rf distPublishing
pnpm publish -r # Publish all changed
pnpm publish -r --no-git-checks # CI modeworkspace:* → actual version on publish.
Related skills
How it compares
Pick pnpm for general Node.js pnpm CI and migration; pick turborepo-monorepo when the repo also needs turbo.json remote cache orchestration.
FAQ
Workspace file?
pnpm-workspace.yaml listing packages apps.
Catalog usage?
Centralized versions referenced as catalog colon in package.json.
Run one package?
pnpm --filter @myorg/app build.
Is Pnpm safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.