pnpm Workspaces
Monorepo package management with pnpm. Fast, disk-efficient, strict dependency resolution.
Source: github.com/pnpm/pnpm · npm Version in project:
9.15.0· Published: 2024-12 · Skill updated: 2026-03-21
When to Use
- Adding, removing, or linking workspace dependencies
- Running scripts with
--filteracross packages - Publishing workspace packages to npm
When NOT to Use
- Running tasks across the monorepo with caching (use
turboreposkill) - Configuring individual package builds (use
tsupskill)
Setup
pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
Install all packages
pnpm install
Workspace Protocol
Reference workspace packages using workspace:*:
{
"dependencies": {
"@ivannikov-pro/app-config": "workspace:*",
"@ivannikov-pro/core": "workspace:*"
}
}
On npm publish, workspace:* is replaced with the actual version.
Common Commands
# Install all workspace packages
pnpm install
# Add dependency to specific package
pnpm add express --filter @ivannikov-pro/server
# Add dev dependency to root
pnpm add turbo -D -w
# Add workspace dependency
pnpm add @ivannikov-pro/app-config --filter @ivannikov-pro/server --workspace
# Remove dependency
pnpm remove lodash --filter @ivannikov-pro/core
# Run script in specific package
pnpm --filter @ivannikov-pro/app-config build
# Run script in all packages
pnpm -r run build
# Run script in root
pnpm run build # (or just pnpm build)
# List all workspace packages
pnpm ls -r --depth -1
# Execute binary from node_modules
pnpm exec tsup
pnpm dlx create-vite # like npx, one-off
Filter Syntax
--filter <package-name> # By package.json "name"
--filter <package-name>... # Package + its dependencies
--filter ...<package-name> # Package + its dependents
--filter ./apps/server # By relative path
--filter {./packages/*} # Glob pattern
--filter "[HEAD~1]" # Changed since last commit
package.json (root)
{
"private": true,
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"clean": "turbo run clean",
"typecheck": "turbo run typecheck"
},
"devDependencies": {
"turbo": "^2.x",
"typescript": "^5.x"
}
}
Publishing Workspace Packages
# Bump version
pnpm --filter @ivannikov-pro/app-config version patch
# Publish to npm
pnpm --filter @ivannikov-pro/app-config publish --access public
⚠️ Gotchas
workspace:* not resolved outside pnpm
workspace:* is a pnpm protocol. If you npm install a published package, pnpm replaces it with the actual version. But you must pnpm publish — plain npm publish won't resolve it.
Hoisting differences from npm/yarn
pnpm uses strict linking — packages can only access dependencies they explicitly declare. If package A depends on lodash but package B doesn't list it, B cannot import lodash (even if it's installed in the root node_modules).
-w flag for root operations
To add/remove dependencies in the root package.json, you must use -w (workspace root):
pnpm add turbo -D -w # ✅
pnpm add turbo -D # ❌ Error: not in a workspace package
pnpm exec vs npx
pnpm exec <bin>— runs from localnode_modules/.bin/pnpm dlx <package>— downloads and runs (likenpx)npxmay resolve differently in pnpm workspaces