What is Yarn, and should we use it?

Update: Since june 2017 and the release of NPM 5, it’s not relevant to use Yarn anymore since the new version of NPM also generates a lock file.

Yarn was initiated by Facebook, and is now supported by major companies like Google. It’s mainly a replacement for package management in your web projects, with a few features missing from the npm CLI. Yarn is fully backward compatible with the npm package manager structure (package.json and node_modules are here to stay).

Before we dive in, I should say that Yarn’s approach is very similar to the PHP package manager Composer. So if you are familiar with Composer, Yarn will be no surprise.

Why Yarn?

There is a few reasons why Facebook decided to setup their own package manager:

  • Yarn is able to work in offline mode. It has a caching mechanism, so dependencies that are loaded once are loaded in Yarn cache. If they are requested a second time, Yarn can fetch them from the cache without loading them from the Internet.
  • Yarn is running the installation in a deterministic mode. The structure of the node modules is exactly the same on every machine where Yarn installation is executed. You will not end up dealing with problems related to having a different installation structure which is often the case with npm.

How it works

The first thing to do is to install Yarn globally on your system using npm (Yarn is available as a NPM package itself).

npm install -g yarn

Now the new Yarn command is available. You can for example run yarn --version to get the currently installed version.

Let’s now initialize a new project. Like the npm init command, Yarn will request some information, like the name of the project, its version, a description, the entry point file, etc.

yarn init

This will create a new package.json in our folder, with the informations we just gave it:

{
"name": "yarn-test-project",
"version": "1.0.0",
"main": "index.js",
"author": "Vincent Ballut",
"license": "MIT",
}

Let’s now add a new dependency to our empty project. The command for that is add, followed by the package name.

yarn add bootstrap-sass
yarn add v0.16.1
info No lockfile found.
[1/4] 🔍 Resolving packages..
[2/4] 🚚 Fetching packages..
[3/4] 🔗 Linking dependencies..
[4/4] 📃 Building fresh packages..
success Saved lockfile.
success Saved 1 new dependency
└─ bootstrap-sass@3.3.7
✨ Done in 1.

Ok, what is happening here?

Yarn is first saying that no lock file is found, which is where Yarn saves everything: adding, removing, or updating packages. That lock file allows Yarn to reproduce the installation steps in the exact same order every time a new instance of the project is installed. You can see that the lock file is saved right after the new dependency has been resolved, fetched, linked and built into the project.

Since we didn’t give any version requirement for Bootstrap, Yarn has fetched the latest version found.

If we go back in our folder, we notice two new entries: the node_modules folder and the yarn.lock file. node_modules contains all the files of our dependencies, just like npm.

The yarn.lock file is auto generated by Yarn. All the dependencies which have been resolved and installed to node_modules are listed here. For each one, it says which version has been installed and from where it was fetched. This file is meant to be part of the project source code, allowing each developer to replicate the exact same installation process when they run yarn install.

If I run yarn install in 3 month, Yarn will install bootstrap-sass version 3.3.7 even if 3.3.8 has been released. If I need to upgrade to 3.3.8, I can run:

yarn upgrade bootstrap-sass

Or, if I just want a specific version:

yarn upgrade bootstrap-sass@3.3.8

When I do that, the yarn.lock file will be modified to reflect that version upgrade, and all my coworkers will now install bootstrap-sass version 3.3.8 when they next run yarn install.

Wrapping up

Yarn seems to be a solid package manager, with some features that always have been missing from the npm ecosystem. It being fully backward compatible, I see no reason not to use it in replacement of the npm CLI.