When should I choose pnpm over npm for a monorepo with shared internal packages? #195562
-
🏷️ Discussion TypeQuestion BodyHi, I'm setting up a monorepo with 4–5 packages that share internal dependencies (a shared utils package used by multiple apps). I've read that pnpm uses a content-addressable store and symlinked node_modules, which saves disk space and improves install speed. My specific concerns are:
I'm not concerned about lockfile portability since the whole team would migrate together. Is pnpm's stricter dependency isolation worth the migration cost for this use case, or does npm's workspace support cover the same ground adequately now? |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments
-
|
For a monorepo with shared internal packages, pnpm is usually the stronger choice once dependency isolation and workspace correctness start mattering more than maximum ecosystem compatibility. Regarding your specific concerns:
It is not mathematically impossible to still create edge cases (especially with custom tooling or incorrect peer dependency setups), but pnpm is significantly stricter and more deterministic than classic npm hoisting.
Using: "my-shared-lib": "workspace:*" |
Beta Was this translation helpful? Give feedback.
-
|
Great question and you've clearly done your research already so let me get straight to the specific things you asked about since the previous answer got cut off. Phantom dependencies — pnpm's strict linking prevents this in the vast majority of real world cases. Each package can only access what it explicitly declares in its own workspace: protocol — this is honestly where pnpm pulls the furthest ahead and it's the most underrated difference. When you use Compatibility — this is the one area worth actually thinking about before migrating. Tools that assume a flat Jest sometimes needs a small config tweak if it can't find packages: // jest.config.js
moduleDirectories: ['node_modules', '<rootDir>/node_modules']Webpack 4 and older can have issues but Webpack 5 handles pnpm's structure fine. Most modern tooling like Vite, Turbopack and tsup works without any changes at all. For your specific setup — 4 to 5 packages with a shared utils is literally the textbook use case pnpm was designed for. The migration cost is low, the |
Beta Was this translation helpful? Give feedback.
-
|
You may consider pnpm because it is generally a better choice for a monorepo with several shared internal packages. Its dependency system is much stricter than npm’s traditional hoisting model. With npm, dependencies are often hoisted into the root node_modules, which means a package can accidentally use libraries it never declared in its own package.json. Compatibility with pnpm has improved greatly in recent years, and most modern tooling such as TypeScript, Vite, Webpack 5, Jest, ESLint, Next.js, and Turborepo now works well with pnpm. However, some older tools and plugins still assume a flat node_modules structure and may require small configuration changes, especially certain Jest setups or React Native projects. For a standard web or TypeScript monorepo, these issues are relatively uncommon today. For your use case, the migration is usually worth it because pnpm gives better dependency correctness, faster installs, lower disk usage, and cleaner separation between packages. npm workspaces are much more capable than they used to be and are perfectly usable for smaller monorepos, but pnpm still provides stronger guarantees and a better developer experience when managing multiple interconnected packages. To start a pnpm monorepo, you would first install pnpm globally using: Then create and initialize the repository: Next, create a pnpm-workspace.yaml file: You can then create your apps and shared packages: Initialize each package: To connect an internal package, add this dependency inside apps/web/package.json: Finally, install everything from the repository root with: After setup, you can run commands across the workspace or target specific packages using filters, which makes managing larger monorepos much easier. |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for your reply, @ALL. I think i have the right answer now |
Beta Was this translation helpful? Give feedback.
-
|
__ |
Beta Was this translation helpful? Give feedback.
-
|
For a monorepo with shared internal packages, pnpm is generally worth it in my experience.
npm workspaces have improved a lot, but npm still behaves more permissively. If your repo is small and the team values simplicity over strictness, npm is adequate. But if you want stronger dependency boundaries and fewer “works on my machine” problems as the repo grows, pnpm is usually the better long-term choice. |
Beta Was this translation helpful? Give feedback.
You may consider pnpm because it is generally a better choice for a monorepo with several shared internal packages. Its dependency system is much stricter than npm’s traditional hoisting model. With npm, dependencies are often hoisted into the root node_modules, which means a package can accidentally use libraries it never declared in its own package.json.
Compatibility with pnpm has improved greatly in recent years, and most modern tooling such as TypeScript, Vite, Webpack 5, Jest, ESLint, Next.js, and Turborepo now works well with pnpm. However, some older tools and plugins still assume a flat node_modules structure and may require small configuration changes, especially certain Jest se…