pnpm "Cannot find module" from strict hoisting (node-linker) in CI
pnpm builds an isolated, symlinked node_modules where a package can only import what it declares. Code that relied on a phantom dependency (something hoisted by npm/Yarn but never declared) fails with "Cannot find module" under pnpm.
What this error means
A build or test step throws "Error: Cannot find module 'X'" for a package that installs fine, and it works under npm or Yarn classic but not pnpm.
Error: Cannot find module 'lodash'
Require stack:
- /home/runner/work/app/app/packages/api/src/index.js
at Function._resolveFilename (node:internal/modules/cjs/loader)Common causes
A phantom (undeclared) dependency
The code imports a package that was never listed in its package.json; npm hoisting made it resolvable, but pnpm's isolated layout does not.
A package expects a flat node_modules
Some tools resolve peers or plugins by walking a flat tree; pnpm's symlinked structure exposes the missing declaration.
How to fix it
Declare the dependency explicitly
- Read the require stack to see which package imports the missing module.
- Add the module to that package's
dependencies. - Re-run
pnpm installso the declared dependency is linked.
pnpm --filter @acme/api add lodashAdjust node-linker or hoisting only if a tool truly needs it
For a tool that cannot work with an isolated layout, switch to a hoisted or flat node_modules rather than papering over undeclared deps.
# pnpm-workspace.yaml (pnpm 9+) or .npmrc
node-linker=hoistedHow to prevent it
- Declare every module you import in the package that imports it.
- Keep
node-linker=isolated(the default) to catch phantom deps early. - Use
public-hoist-patternsparingly and only for known-incompatible tools.