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