--- name: pnpm-workspaces description: 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: ```yaml 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: ```json { "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`: ```bash # 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 ```bash # 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 ```bash # 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 ```bash # 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 ```bash # Run command in all packages pnpm -r exec pwd # Run in specific packages pnpm --filter "./packages/**" exec rm -rf dist ``` ## Workspace Settings Configure in `.npmrc` or `pnpm-workspace.yaml`: ```ini # Link workspace packages automatically link-workspace-packages=true # Prefer workspace packages over registry prefer-workspace-packages=true # Single lockfile (recommended) shared-workspace-lockfile=true # Workspace protocol handling save-workspace-protocol=rolling # Concurrent workspace scripts workspace-concurrency=4 ``` ## Publishing Workspaces When publishing, `workspace:` protocols are converted: ```json // Before publish { "dependencies": { "@myorg/utils": "workspace:^" } } // After publish { "dependencies": { "@myorg/utils": "^1.2.3" } } ``` Use `--no-git-checks` for publishing from CI: ```bash pnpm publish -r --no-git-checks ``` ## Best Practices 1. **Use workspace protocol** for internal dependencies 2. **Enable `link-workspace-packages`** 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 ## 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 ```