Jan 10, 2023 • 6 min read

YARN, PNPM, and NPM: What to Choose in 2023

author picture
Jay Khatri
Co-founder, Hype-man & CEO

Any developer working with JavaScript will sooner or later encounter the need to use a command line package manager to install a variety dependencies, libraries and configurations. What you may or may not know is that there is a bit of a debate going on as to which package manager is “best”. Of course, “best” is a completely relative term, so I’m going to do my “best” to examine the top three contenders in the package manager universe. What makes each of them unique?

YARN

In 2016, Facebook released the Yarn package manager as an alternative to NPM, the default package manager used in the NodeJavaScript runtime environment. Yarn stands for Yet Another Resource Negotiator, and was developed to address performance issues that were lacking with NPM, such as lengthy install times.

In order to speed up installation times, Yarn utilizes parallel dependency installation, where multiple packages are downloaded and installed into the project environment at the same time. This differs significantly from NPM, which installs sequentially, one package at a time. Installing in parallel equals faster speed, meaning developers can get on with developing rather than waiting for code dependencies to install. However, this is where relative terms such has “faster” and “best” come into play…

I have used Yarn in some development projects, and it does seem like parallel installation is faster than NPM’s sequential process…sometimes. Download and installation times are dependent upon so many relative factors, such as internet connection speed, network settings, and computer hardware, to name a few. To calculate exact speed differentials based solely upon parallel dependency installation would take an in-depth double-blind placebo-controlled (so to speak) study that hasn’t been conducted to this point.

There is another feature unique to Yarn that I am personally a big fan of, called Plug ’n Play. Instead of generating a large node_modules folder to store downloaded packages, Yarn creates a .pnp.js file in the project folder in order to map where installed packages and their dependencies are stored on your local disk. Yarn then uses a single call from the require() function which is used by Node to find the dependencies. This confers a huge benefit because not only does this eliminate the need for a huge node_modules folder, saving significant disk space (perhaps 100MB or more per project), but it also means that installed modules can be pulled in from the global cache. Using the package cache also speeds up build times, since the dependencies are already hanging out in memory, rather than having to retrieve calls to various node_modules files.

PNPM

Speaking of node_modules, PNPM is a package manager that was also first released in 2016 that is built on top of NPM. PNPM features an interesting approach to the node_modules structure by using content-addressable storage. This begs the question, what is content-addressable storage? The concept is very simple: a single permanent location address is created to store all of the downloaded dependencies and is then linked to by a symlink (Symbolic link), which is merely a shortcut pointing to that address on disk.

With PNPM, a single global store is created as a hidden file (.pnpm-store) that contains the actual downloaded dependency. Whenever a package is added to a project, symlinks are generated inside of a single .pnpm folder that point to those dependencies in the global store, saving disk space. The node_modules folder is still there, but the symlinks within the .pnpm folder act as a “virtual store”, so that the actual dependencies can be used from a single centralized location elsewhere rather than redundantly storing package files in multiple projects.

This nested dependency structure also makes for a faster installation experience, as package files that are already installed on disk are not installed again, unlike with Yarn and NPM. Developers who work with a wide variety of new packages will obviously still encounter wait times, but those who use the same packages over and over again will notice the improved speed. For example, creating a new [React](https://reactjs.org/) project with npm-create-react-app is notorious for slowly downloading and installing the necessary package dependencies. With PNPM, the nested sharing of dependencies via symlinks can help cut out much of the bloat that is inherent to the process, perhaps justifying it’s name as “Performant NPM”./

The primary downside of PNPM is that some older packages simply may not work with the nested dependency structure. If you work with a lot of legacy code, this could be an issue that necessitates sticking with NPM, which is always backwards-compatible.

NPM

The original package manager for Node is simply titled NPM, for Node Package Manager and was first released in 2010. Over the years, NPM has consistently been updated with security features as well as faster performance improvements than earlier versions. Starting with version 6.0, NPM conducts an audit for security and dependency conflicts, as well as generating a .package-lock.json file to guarantee or “lock” the dependencies to the installed versions. This lock file makes sure that exact version numbers are used in the node_modules folder, so that multiple developers working on the same project are all using the same packages and dependencies, thereby avoiding conflicts and chaos.

NPM installs dependencies sequentially, so if you are downloading large packages (such as React) you will likely have time to eat a doughnut or drink your juicebox while they download and install. However, with most packages the sequential installation process is pretty quick in newer versions of NPM compared to a few years ago. Again, speed is relative to the situation, so there is no one-size-fits-all answer.

Perhaps the biggest advantage to using NPM is the large support base behind it. Should you happen to run into a bug or issue when using NPM, a quick online search will yield answers to nearly any questions that may arise. NPM, Inc. was acquired by GitHub in 2020, and hosts the NPM registry, an online platform where open-source packages can be published and shared. The sheer size of this community makes it likely that ongoing support and development of NPM will continue into the foreseeable future.

So, which package manager is "best"?

Do you work on a team of developers? NPM is likely the easiest to use, since it is bundled with every Node installation and developers should already be very familiar with it. This saves on time needed to configure and learn a new methodology, and the large community behind it can quickly help resolve any problems. PNPM is great for solo developers and freelancers such as myself, who put a premium on disk space. I personally don’t have the means to constantly expand my disk storage space, so utilizing PNPM’s content-addressable storage saves me both space and time on installations. Yarn is also a good solution for solo developers or small teams who may be able to save on install times because of the parallel installation architecture. Yarn can also cut back on disk storage by taking advantage of the Plug ’n Play global caching feature, eliminating the bloated node_modules folder altogether.

Personally, I find PNPM to be the best overall solution, as it resolves both speed issues as well as disk and project bloat, while keeping the familiarity of NPM. All three of these package managers are easy to use, relatively fast, and secure overall, so the one you choose will likely come down to the situation that you work in. Thus, there can be no “one package manager to rule them all” in 2023.

Other articles you may like

Introducing: Frontend Monitoring by Highlight
The beauty of contract-first API design
Publishing an NPM Package with Private pnpm Monorepo Dependencies
Try Highlight Today

Get the visibility you need