Module not found β package exists in node_modules but can't be resolved
What causes this
pnpm uses a strict node_modules structure where packages can only access their declared dependencies. This is correct behavior β it prevents βphantom dependenciesβ (using packages you didnβt explicitly install). However, some packages are poorly written and rely on npm/yarnβs flat node_modules structure to access undeclared dependencies.
Common scenarios:
- A package imports a peer dependency it didnβt declare
- A Webpack/Vite plugin tries to resolve modules from the project root
- ESLint or Prettier plugins that expect flat
node_modules - Monorepo packages accessing dependencies from the root
Fix 1: Hoist specific packages (recommended)
Instead of hoisting everything, only hoist the packages that need it:
# .npmrc
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*
public-hoist-pattern[]=@types/*
Then reinstall:
rm -rf node_modules
pnpm install
Fix 2: Use shamefully-hoist (quick fix)
This makes pnpm behave like npm β flat node_modules:
# .npmrc
shamefully-hoist=true
rm -rf node_modules
pnpm install
This works but defeats pnpmβs strictness. Use it as a temporary fix while you figure out which packages actually need hoisting.
Fix 3: Add the missing dependency explicitly
The cleanest fix β if package A needs package B but doesnβt declare it, install B yourself:
# Check what's missing
pnpm why missing-package
# Install it explicitly
pnpm add missing-package
Fix 4: Use pnpmβs node-linker option
# .npmrc β use npm-style flat node_modules
node-linker=hoisted
This changes pnpmβs linking strategy entirely. Less strict than default, more strict than shamefully-hoist.
Fix 5: Report the bug upstream
If a package doesnβt declare its dependencies properly, itβs a bug in that package. Open an issue:
The package imports X but doesn't list it in dependencies or peerDependencies.
This breaks with pnpm's strict node_modules structure.
Many maintainers fix this quickly once reported.
How to prevent it
- Start with strict mode (pnpmβs default) and only add hoisting for specific packages that need it
- Use
public-hoist-patterninstead ofshamefully-hoistβ itβs more targeted - When evaluating new packages, check if they work with pnpm before committing to them
- Consider using pnpm vs npm to understand the tradeoffs