← Recipes

阅读中文版本

Bootstrap a pnpm Monorepo with Workspace Protocol

Create a pnpm workspace with shared tooling, declare cross-package dependencies with the workspace protocol, and verify that changes in one package rebuild dependents.

~30 minpnpmmonorepotooling

Task

Set up a pnpm monorepo where local packages depend on each other through the workspace protocol and a change in one rebuilds its dependents.

When to use this

Three packages share a common logger and a config loader. Today they copy code between repos, so a fix in one lands days late in the others. The team wants a single repo with shared tooling.

Prerequisites

  • pnpm 9 or later installed globally
  • Node.js 20 LTS
  • A git repository with an initial commit

Steps

1. Create the workspace manifest and declare the packages directory.

// pnpm-workspace.yaml
packages:
  - "packages/*"
  - "apps/*"

Expected output: pnpm list --depth -1 shows the workspace root and recognizes the packages and apps globs.

2. Add a shared package and reference it from a consumer using the workspace protocol.

// apps/web/package.json
"dependencies": {
  "@repo/logger": "workspace:^"
}

Expected output: pnpm install symlinks @repo/logger into apps/web/node_modules and the import resolves.

3. Run a build that depends on the shared package and confirm a change propagates.

pnpm -r --filter=web... build

Expected output: Editing the logger source and rerunning the build produces a changed web bundle.

Troubleshooting

Problem

workspace:^ does not resolve

Solution

Confirm the shared package name in its package.json matches the dependency key exactly, including the @repo scope.

Problem

Builds run in the wrong order

Solution

Use the ... filter syntax to include dependents, or run pnpm -r --sort rebuild to respect topological order.

Limitations

  • The workspace protocol only resolves inside the same workspace; publishing requires replacing it with a real version.
  • pnpm does not hoist by default, so a package that relies on phantom dependencies may break.

One repo, one toolchain

A pnpm workspace lets every package share the same lockfile, the same TypeScript config, and the same test runner. Cross-package dependencies use the workspace protocol so a local edit is visible immediately, without a publish round-trip.

# pnpm-workspace.yaml
packages:
  - "packages/*"
  - "apps/*"

Wire the dependencies

Reference a local package with workspace:^ and pnpm symlinks it into the consumer. A change in the logger is visible to the web app on the next build, no version bump required.

{
  "dependencies": { "@repo/logger": "workspace:^" }
}

Expected outcome

pnpm -r build builds packages in topological order, a change in @repo/logger rebuilds apps/web, and the lockfile stays single and shared across the whole workspace.