Like many people who work with node applications, the package manager journey is shaped by whatever solved the biggest pain at the time.
I started with npm, because, that’s where everyone starts.
After npm I moved to Yarn during the period where npm installs felt slow and unreliable, especially when working on larger projects and React Native environments. Yarn brought faster installs, lockfile consistency, and generally felt more stable for day-to-day work.
At the time, it genuinely improved the developer experience.
But over the last few years, npm improved a lot, and the ecosystem changed again. That’s when I discovered pnpm. What immediately stood out with pnpm was how much more efficient it feels.
Instead of copying the same dependencies into every project, pnpm uses a content addressable store and links packages into projects, which in practice means:
- less disk usage
- faster installs across multiple projects
- cleaner dependency management
- and better enforcement of dependency correctness
The last point is surprisingly important.
The pnpm package manager exposes dependency issues that npm and Yarn sometimes let slide. Packages that rely on undeclared transitive dependencies tend to break faster under pnpm, which at first sounds annoying, but in my experience have resulted in healthier projects.
For my node applications and automation tooling, pnpm has become the default.
I still use npm when needed, and Yarn still makes sense in some ecosystems, like older React Native setups. But if I am starting a new node project today, pnpm is usually where I begin. Not because npm or Yarn are bad, but because pnpm just feels like the package manager most aligned with how modern JavaScript projects should work.