When installing packages to a Node.js project, many people stick with the default npm. Many people also use its alternative, yarn, but few know about more uncommon ones like pnpm or dry.
Weekly downloads according to npm: 1.8 million.
npm (created in 2010) is the “world’s largest package registry” (as written here) and it is the package manager installed with Node.js. Although it is probably the most popular one and well maintained, many people complain about missing some features.
npm uses the
Unique features of npm:
npx– run package without installing it (an equivalent is not available in Yarn 1)
npm 6 (2018)
npm audit– discover vulnerable packages
npm ci– faster and more reliable way to install the project
npm 7 (upcoming in 2020):
npm link– create symbolic links to packages
npm ls– equivalent of
- workspaces similar to Yarn’s
- it will cooperate with Yarn’s
- ability to install or run a pull request package:
npm install github:username/reponame#pull/123
Weekly downloads according to npm: 1.3 million.
Probably the second most popular package manager is yarn. It was created by Facebook in 2016 to address some problems with npm they had. From the beginning, it provided no fewer features than npm and also included some great ideas that were later incorporated into npm (e.g. lock file with versions, caching).
Yarn uses the
What are Yarn‘s benefits?
yarn <script>instead of
npm run <script>
yarn upgrade-interactive– upgrade only selected packages
yarn licenses ls– inspect licenses uses of all dependencies (for other package managers it’s possible to use license-checker)
yarn why– find out why given package was installed
.yarnclean– automatically remove given files from installed packages in
node_modulesto save space, like documentation, tests, build scripts
- support for workspaces to easier manage dependencies in monorepos
- Plug’n’Play is a new mode of running Node.js applications without the
node_modulesfolder. Instead, packages are stored in a special folder one file per dependency, and there is an index file used to resolve them. It greatly increases performance and reduces disk usage.
In January 2020, a new version of yarn was published. Although it’s not fully compatible with all packages yet (React Native), the previous version will not be further developed. It adds the following new items:
- Zero-Installs – modules cache will be by default stored in the project’s directory, though it can be changed in the options. That compressed cache can be added to the repository (along with a couple of other files) and used to run the project immediately after checking out, without the need of downloading or installing packages. This new mode of running Node.js applications is called Plug’n’Play. It also greatly increases performance and reduces disk usage.
yarn dlxdoes the same as
- updated workspaces and CLI
- ability to locally patch downloaded packages (docs)
- dependencies as symlinks (docs)
- shell interpreter for
scriptssection, allowing to use one syntax for all OSes
Weekly downloads according to npm: 63 thousand.
One of the biggest problems with npm is the amount of space required by projects using the same dependencies. Package manager pnpm comes with a solution. Instead of creating copies of packages in every project, it downloads them to a global cache and creates only symlinks and hard links in the projects. This way space is taken only once per given package.
I’m curious what are the actual savings due to multitude of versions of dependencies used in various projects. Different versions won’t enable the reuse of packages, and we have to remember about dependencies of the dependencies, with different versions again.
pnpm uses the
Unique features of pnpm:
- every package version is downloaded only once and linked to from projects using it
pnpmuses the same arguments as
pnpxis the equivalent of
Weekly downloads according to npm: 1 thousand.
I came along dry when I wanted to find a solution for inhering parts of
package.json scripts (dependencies or scripts). It states to solve this inconvenience by allowing to inherit configurations. Its name means DRY = Don’t Repeat Yourself.
Every time the
dry is executed, it creates a merged
package.json file, runs the
npm command, patches
package-dry.json file with changes made to
npm, and finally removes the
package.json file to avoid working on it directly.
dry uses the
package-lock.json and, temporarily,
Unique features of dry:
- inheritance of
dryuses the same arguments as
There is no single winner for all cases. I think that in most projects, the difference won’t be very noticeable – after all, what is the ratio of changing dependencies (when package manager matters) to building a project (when it usually does not)?