Skip to main content

From npm to yarn to pnpm - the why, what and how

This blog post might be outdated!
This blog post was published more than one year ago and might be outdated!
· 3 min read
Daniel Ruf
Full Stack Developer

There are a few package managers for Node.js projects and some of them provide advantages over others. Currently, we use yarn and we face some challenges, that may be solved by migrating to pnpm.

Since we migrated all projects from npm to yarn v1 (Classic) we have more robust and faster development setups and fewer issues compared to our npm-based setup. Before this developers and projects often used different npm versions which also introduced breaking changes and different lock files per version. This has led to many cases where we had to debug developer setups.

Until now we are very satisfied with yarn v1 (Classic) and do not plan to move to a new major version of yarn, because these only introduce new features that we do not need. And new features like yarn PlugnPlay may lead to new problems.

Besides that, we have many projects with the same dependencies. So the exact same files exist in multiple locations. In sum, the node_modules folders consume multiple GB of disk space. That is not very economic and a waste of resources.

From my time as a maintainer of opensource projects and working on verdaccio I already knew about pnpm, which is a performant npm alternative.

Technically pnpm creates a central content-addressable storage of all the files that are then put into node_modules folders, but all these files are hard links that point to the real files in this storage. So in the end the same files exist only once on the disk, which drastically reduces the used disk space.

Additionally, the layout of the node_modules folder is a bit different from pnpm. Only top-level dependencies are in this folder. This is helpful because if we try to import and use a deeply buried dependency in our code that is not registered in the top-level package.json file, then this will throw an error. This prevents surprises when the optimistically imported dependency is removed from a deeply nested dependency and we are not aware of this.

For yarn v3 and newer, there is a similar solution with the pnpm linker mode, but this is still not fully implemented.

Check the following links, if you want to learn more about the different linker solutions in yarn:
https://dev.to/arcanis/yarn-31-corepack-esm-pnpm-optional-packages--3hak#new-install-mode-raw-pnpm-endraw-
https://dev.to/arcanis/yarn-3-0-performances-esbuild-better-patches-e07 (hardlinks-global)
https://dev.to/arcanis/yarn-31-corepack-esm-pnpm-optional-packages--3hak (pnpm linker)
https://dev.to/arcanis/yarn-32-libc-yarn-explain-next-major--o22
https://yarnpkg.com/getting-started/migration

The migration from yarn to pnpm is quite easy. You can try one of these routes:

  • either you run pnpm import which imports and converts the lock file of yarn
  • you remove the yarn.lock file and the node_modules folder and then run pnpm install

This will then create a new lock file pnpm-lock.yaml. The old lock file can be removed after this.

pnpm will tell you after the install step, if it will detect any issues like missing or wrong dependencies and provide you with the relevant commands, to resolve these issues. When you do a pnpm run start or pnpm start and your project throws errors due to missing dependencies, then you might have to check and install these too.

In the end, you will have an even more robust and secure project setup, much lower disk usage, and a better developer experience. And as a bonus, the current features also replace some dependencies for us, for example, patch-package for in-place patching of dependencies.

Do something good for the planet, the security, and your team members. Move to pnpm now.