ADR 004: pnpm as Package Manager
Status: Accepted Date: 2025-03-15 Last Updated: 2026-02-26
Context
We need a package manager for both the monorepo and the MFE polyrepos. It must support workspaces, be fast, and handle the complexities of Module Federation shared dependencies correctly.
Decision
Use pnpm 10.30.3 across all repositories. Pin via Corepack ("packageManager": "pnpm@10.30.3" in root package.json).
pnpm 10 Migration Notes
pnpm 10 introduces several breaking changes from pnpm 9.x that must be addressed:
Lifecycle Scripts Disabled by Default
In pnpm 10, pre/post lifecycle scripts (e.g., preinstall, postinstall, prepare) are no longer run by default. To restore the previous behavior, either:
- Add
enable-pre-post-scripts=trueto.npmrcin each repository root, or - Use the
onlyBuiltDependenciesallowlist inpackage.jsonto explicitly permit specific packages to run install scripts (recommended for security).
Hoisting Changes
pnpm 10 changes the default hoisting behavior. The public-hoist-pattern defaults have been narrowed. For Module Federation shared dependencies, ensure .npmrc explicitly sets:
public-hoist-pattern[]=*types*
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=react
public-hoist-pattern[]=react-dom
Other pnpm 10 Migration Considerations
- The
resolution-modedefault changed tohighestin pnpm 10. If you relied onlowest-direct, set it explicitly in.npmrc. pnpm-lock.yamlformat has been updated (lockfile v9). The firstpnpm installafter upgrading will migrate the lockfile automatically. Commit the updated lockfile.- The
--filterflag behavior has been tightened; verify workspace filter scripts still work after upgrading. - Node.js 18 is the minimum required version for pnpm 10.
Consequences
Positive
- Content-addressable store: packages stored once on disk, hard-linked into node_modules (saves significant disk space)
- Strict dependency isolation by default (can't accidentally use undeclared dependencies)
- Native workspace support with
workspace:*protocol - Faster installations than npm/yarn in most benchmarks
pnpm-lock.yamlis deterministic and easier to review than package-lock.json- Built-in support for .npmrc overrides per workspace
- Corepack-compatible for version pinning (pnpm 10.30.3)
Negative
- Strict node_modules structure can cause issues with tools that expect flat hoisting (Module Federation shared deps, some legacy packages)
- Requires
.npmrcconfiguration for public-hoist-pattern to work with MF shared dependencies - Smaller community than npm (though growing rapidly)
- Some CI environments don't have pnpm pre-installed (need corepack enable or pnpm/action-setup)
- pnpm 10 disables lifecycle scripts by default, requiring explicit
.npmrcconfiguration oronlyBuiltDependenciesallowlist
Alternatives Considered
- npm: Ubiquitous but slow, flat node_modules causes phantom dependencies, workspace support is less mature. No content-addressable store.
- yarn (v3/v4 with PnP): Plug'n'Play is innovative but causes compatibility issues with many tools (especially Module Federation, which expects node_modules). Berry (v3+) has a steep learning curve. Classic yarn (v1) is in maintenance mode.
- yarn (v1 classic): Mature and stable but no longer actively developed. No content-addressable store, no strict dependency isolation.
- Bun: Fast but still maturing, not all Node.js APIs supported in Workers context, workspace support still evolving.