Files
moeka-project/.agents/skills/pnpm/references/core-workspaces.md
T

4.6 KiB

name, description
name description
pnpm-workspaces Monorepo support with workspaces for managing multiple packages

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 build

Dependency-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]" lint

Workspace 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/utils

Run 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 dev

Execute commands

# Run command in all packages
pnpm -r exec pwd

# Run in specific packages
pnpm --filter "./packages/**" exec rm -rf dist

Workspace 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

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

Best Practices

  1. Use workspace protocol for internal dependencies
  2. Enable linkWorkspacePackages for automatic linking
  3. Use shared lockfile for consistency
  4. Filter by dependencies when building to ensure correct order
  5. Use catalogs for shared external dependency versions (defined in this same file)
  6. 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