Yarn: Lock It in for Deterministic Dependency Resolution

Choices are an important part of a healthy open source software community. That's why we're excited about Yarn, a new package manager that addresses many of the problems with Node's default package manager, npm. While npm has done a fantastic job creating a large and vibrant JavaScript ecosystem, I want to share why Yarn is an important addition to the Node.js ecosystem, how it will improve your Node.js development experience, and how Heroku has incorporated it into the build process for your Heroku apps.

We began testing Yarn almost immediately after it was released, and began fully supporting it on December 16.

A few popular projects have switched to Yarn. Ruby on Rails in version 5.1 switched to using Yarn by default. JHipster, a Java web app generator that incorporates Spring Boot, Angular, and Yeoman, has switched to Yarn too.

Yarn improves several aspects of dependency management for Node developers. It pulls packages from the npm registry (via a proxy), which gives you access to the same huge selection of packages available via npm. But Yarn gives you three big benefits:

Predictable installs

Security as a core value

Performance

Let's look at each in more detail.

Adding a new dependency to a Node project can sometimes be a torturous task. It has become far too common for Node developers to resort to rm -rf node_modules && npm install after encountering errors adding a new dependency to a project. You can kiss those days goodbye with Yarn. An explicit design goal of Yarn is deterministic dependency resolution.

What is deterministic dependency resolution? Think of a pure function. If the same inputs go into a pure function, the same outputs always come out. Dependency resolution should work the same way. If the same dependency list goes in, the same node_modules folder should come out.

We want to make every deploy on Heroku a low risk event. It should be a fast and common part of your everyday development workflow. We also want to encourage dev / prod parity-the code that runs in your development environment should be exactly what runs in production.

Running npm install on two different machines can result in different dependencies being installed on each machine. These two machines could be two developer machines. Or, much more problematic, they could be a development machine and a production machine. The crux of this is that the dependency tree npm generates is determined by the order in which packages are installed. For more detail on this, I suggest you read this page from npm's documentation.

Yarn's lockfile is the key component making its dependency resolution deterministic. Using the lockfile, Yarn will generate the same dependency tree regardless of install order. This means it's important that you commit your yarn.lock file to source control.

How do you know every time you or your deploy process runs npm install you're getting the same code you got the first time? With npm, you don't. For example, you might have a faulty cache or there might be an issue with the proxy you're using. npm will install that different code and not provide a warning or error.

Yarn inspects the integrity of each package every time it is installed. It calculates a checksum to ensure you always get the same bits for a specified version of a package. If one line of code changes in left-pad v1.1.2, Yarn's next install of left-pad will fail.

While build predictability and security are most important to us, fast dependency installation provides some great benefits. We want your deploys on Heroku to be fast -- regardless of whether you're deploying a Review App, staging app, or production app. But even on your local development machine, Yarn will get you faster initial project setup and faster addition or upgrade of dependencies. It means you can more easily stay undistracted in your flow state.

Whereas npm downloads dependencies sequentially, Yarn downloads, compiles if necessary, and installs multiple dependencies in parallel. Most computers and network connections these days are capable of installing more than one dependency at a time.

So are you excited about Yarn yet? If not, here are a few more Yarn features that have been useful to me:

Heroku has full support for Yarn. Any Node.js app with a yarn.lock file will be built using Yarn instead of npm. Without any additional work, using Yarn on Heroku will get you predictable, secure, and, possibly, faster deploys. Of course, if you want or need to continue using npm, you can.

If you haven't used Yarn yet, I encourage you to check out the getting started guide. It took me just a few minutes to swap out npm for Yarn on several existing projects, and just a few more minutes to figure out Yarn's simple commands.