pnpm Workspaces
pnpm has built-in support for monorepos (multi-package repositories) through workspaces.
Setting Up Workspaces
Create pnpm-workspace.yaml at the repository root:
packages:
# Include all packages in packages/ directory
- 'packages/*'
# Include all apps
- 'apps/*'
# Include nested packages
- 'tools/*/packages/*'
# Exclude test directories
- '!**/test/**'Workspace Protocol
Use workspace: protocol to reference local packages:
{
"dependencies": {
"@myorg/utils": "workspace:*",
"@myorg/core": "workspace:^",
"@myorg/types": "workspace:~"
}
}Protocol Variants
| Protocol | Behavior | Published As |
|---|---|---|
workspace:* |
Any version | Actual version (e.g., 1.2.3) |
workspace:^ |
Compatible version | ^1.2.3 |
workspace:~ |
Patch version | ~1.2.3 |
workspace:^1.0.0 |
Semver range | ^1.0.0 |
Filtering Packages
Run commands on specific packages using --filter:
# By package name
pnpm --filter @myorg/app build
pnpm -F @myorg/app build
# By directory path
pnpm --filter "./packages/core" test
# Glob patterns
pnpm --filter "@myorg/*" lint
pnpm --filter "!@myorg/internal-*" publish
# All packages
pnpm -r build
pnpm --recursive buildDependency-based Filtering
# Package and all its dependencies
pnpm --filter "...@myorg/app" build
# Package and all its dependents
pnpm --filter "@myorg/core..." test
# Both directions
pnpm --filter "...@myorg/shared..." build
# Changed since git ref
pnpm --filter "...[origin/main]" test
pnpm --filter "[HEAD~5]" lintWorkspace Commands
Install dependencies
# Install all workspace packages
pnpm install
# Add dependency to specific package
pnpm --filter @myorg/app add lodash
# Add workspace dependency
pnpm --filter @myorg/app add @myorg/utilsRun scripts
# Run in all packages with that script
pnpm -r run build
# Run in topological order (dependencies first)
pnpm -r --workspace-concurrency=1 run build
# Run in parallel
pnpm -r --parallel run test
# Stream output
pnpm -r --stream run devExecute commands
# Run command in all packages
pnpm -r exec pwd
# Run in specific packages
pnpm --filter "./packages/**" exec rm -rf distWorkspace Settings
Configure in pnpm-workspace.yaml using camelCase keys (these settings no longer belong in .npmrc):
packages:
- 'packages/*'
# Link workspace packages automatically
linkWorkspacePackages: true
# Prefer workspace packages over registry
preferWorkspacePackages: true
# Single lockfile for the whole workspace (recommended)
sharedWorkspaceLockfile: true
# Workspace protocol handling on publish
saveWorkspaceProtocol: rolling
# Concurrent workspace scripts
workspaceConcurrency: 4
# Use root deps to resolve peers of all projects
resolvePeersFromWorkspaceRoot: true
# Scripts required in every project (else `pnpm -r run <name>` fails)
requiredScripts:
- build
# Downgrade dependency-cycle warnings; also turns ERR_PNPM_TASK_CYCLE into a warning
ignoreWorkspaceCycles: false
linkWorkspacePackages: truelinks a workspace project only where a project declares it directly; a transitive plain-range dep still comes from the registry. Usedeepto link workspace projects into subdependencies too.
Cross-project task graphs
pnpm -r run <script> schedules a dependency-aware task graph. Declare relationships under tasks (with dependsOn, concurrencyGroups, priority) and run cached CI-style pnpm pipeline. See features-task-orchestration.
tasks:
build:
dependsOn: ['^build'] # build each workspace dependency first
test:
dependsOn: ['build']Per-package configuration (packageConfigs)
There are no per-subproject .npmrc files. Set package-specific settings from the root file:
packageConfigs:
project-1:
saveExact: true
project-2:
savePrefix: '~'Publishing Workspaces
When publishing, workspace: protocols are converted:
// Before publish
{
"dependencies": {
"@myorg/utils": "workspace:^"
}
}
// After publish
{
"dependencies": {
"@myorg/utils": "^1.2.3"
}
}Use --no-git-checks for publishing from CI:
pnpm publish -r --no-git-checksBest Practices
- Use workspace protocol for internal dependencies
- Enable
linkWorkspacePackagesfor automatic linking - Use shared lockfile for consistency
- Filter by dependencies when building to ensure correct order
- Use catalogs for shared external dependency versions (defined in this same file)
- Keep all pnpm settings in
pnpm-workspace.yaml(camelCase), not.npmrc
Example Project Structure
my-monorepo/
├── pnpm-workspace.yaml
├── package.json
├── pnpm-lock.yaml
├── packages/
│ ├── core/
│ │ └── package.json
│ ├── utils/
│ │ └── package.json
│ └── types/
│ └── package.json
└── apps/
├── web/
│ └── package.json
└── api/
└── package.json<!--
Source references:
- https://pnpm.io/workspaces
- https://pnpm.io/filtering
- https://pnpm.io/workspace-task-orchestration
-->