Skip to main content

Release: Yarn 4.0 ๐Ÿช„โš—๏ธ

ยท 9 min read
Maรซl Nison
Lead Yarn maintainer

Today is the day! After more than a year of work, our team is excited to finally put a fancy "stable" sticker on the first release from the 4.x release line! To celebrate, let's make together a tour of the major changes; should you look for a more itemized list, take a look at the changelog.

Breaking Changesโ€‹

Here's what you need to know when upgrading from 3.x projects:

  • We now require Node.js 18+.
  • New projects created with yarn init won't enable Zero-Install by default anymore.
  • New projects created with yarn init will use Corepack rather than yarnPath.
  • All official plugins (typescript, interactive-tools, ...) are now included by default.
  • The yarn workspaces foreach command has a slightly altered syntax.

Installing Yarnโ€‹

Ever since the 2.0 our recommendation has been to install Yarn on a per-project basis using the yarnPath setting (automatically set either of yarn init -2 and yarn set version). We intentionally don't release modern releases on the npm yarn package, so as not to break older projects which didn't migrate yet.

To that end we used to recommend using the yarnPath setting pointing to a checked-in binary, but this pattern increased friction more than we liked - many people didn't like the idea of adding a binary to their repository, however small. We listened, and worked conjointely with Node.js on a project called Corepack. Corepack is a tool shipped with Node.js 16+ that will automatically select the right package manager version to run depending on the project you're working on.

Now that Corepack is shipped with both Node 18 and 20 we no longer need to rely on yarnPath, and as a result we updated our installation guide to reflect that. The yarn init -2 and yarn set version commands have been updated to favor updating the packageManager field when possible.

info

Corepack knows which package manager version to use thanks to the standard packageManager field in your package.json. This field will typically be set via one of yarn init -2, yarn set version x.y.z, or the more generic corepack use yarn@x.y.z.

Hardened Modeโ€‹

Yarn attempts to protect you from common attacks, and this is pushed even further by the introduction of the Hardened Mode. When operating under this mode, Yarn will perform two extra validations:

  • It will validate the resolutions stored in the lockfile are consistent with what the ranges could resolve to.
  • It will validate that the package metadata stored in the lockfile are consistent the remote registry metadata.

Together, those checks will prevent any attacker from surreptitiously modifying your lockfiles when making PRs to your project using Yarn (https://snyk.io/blog/why-npm-lockfiles-can-be-a-security-blindspot-for-injecting-malicious-modules/).

tip

The Hardened Mode is enabled by toggling on enableHardenedMode, but it's also automatically enabled when Yarn detects that it runs within a GitHub pull request on a public repository. This can be disabled by explicitly toggling off enableHardenedMode in your yarnrc file.

warning

Installs operating under Hardened Mode constraints are significantly slower than usual as they need to perform many network requests that would be skipped otherwise. We don't recommend enabling it by default - if you need it in a specific CI job, toggle it on via an environment variable:

export YARN_ENABLE_HARDENED_MODE=1

JavaScript Constraintsโ€‹

Yarn is the only package manager to implement a constraints engine. If you don't know it, this feature lets you define a set of rules that your project must satisfy. For instance, the Yarn repository enforces that no two workspaces depend on different versions of any given dependencies, unless explicitly allowed.

Our constraints engine used to be powered by Tau-Prolog, a JavaScript Prolog implementation. Unlike imperative languages like JavaScript, Prolog uses a different model called logic programming - you define that something exists if a rule is true. It's a very interesting pattern that integrates well with the concept of rule-based linting. Unfortunately, Prolog proved very complex to use, increasing the learning curve of constraints past the threshold we were comfortable with.

As a result, Prolog constraints are deprecated starting from Yarn 4, and they have been superseded by a shiny new JavaScript-based engine, with optional TypeScript support! We have been writing our own rules at Datadog with this framework for a couple of months now, with great success. You can also check the public Yarn repository for a practical example of the kind of rules you can enforce at the repository level, and the newly revamped documentation is there to help you quickly get up to speed.

tip

The new optional enableConstraintsChecks setting will make Yarn run your constraints as part of yarn install. It's a handy way to surface errors before having to wait for the remote CI to raise them, and since the new engine is so fast, it has almost no impact on your install time ๐Ÿš€

TypeScript Integration, Interactive Tools, ...โ€‹

Various features in Yarn used to be shipped as sideloaded plugins that needed to be managed separately from the main bundle. While this helped us build a plugin ecosystem, it also proved challenging to manage for our users. We implemented some features to make that easier (auto-upgrade plugins when you auto-update Yarn), but in the end the few KiBs we gained by not shipping all the features by default weren't worth the confusion and friction they caused.

As a result, while Yarn still supports third-party plugins (and will continue to in the future), all the features and commands we build are now available as part of the main distribution. You can now use yarn upgrade-interactive and yarn stage without plugins and, if you have TypeScript configured in your project, Yarn will now auto-add and remove @types packages as needed whenever you update your dependencies with yarn add and yarn remove.

Improved User Interfaceโ€‹

Various pieces of the UI got revamped to better convey information. For example, yarn install now tells you the packages you added, and their total weight. You will also notice it doesn't print as much warnings around peer dependencies, as we now try to only print warnings for actionable situations:

โžค YN0000: ยท Yarn 4.0.0
โžค YN0000: โ”Œ Resolution step
โžค YN0085: โ”‚ + next@npm:13.5.4, react-dom@npm:18.2.0, and 24 more.
โžค YN0000: โ”” Completed in 0s 280ms
โžค YN0000: โ”Œ Fetch step
โžค YN0013: โ”‚ 22 packages were added to the project (+ 177.72 MiB).
โžค YN0000: โ”” Completed in 3s 723ms
โžค YN0000: โ”Œ Link step
โžค YN0000: โ”” Completed
โžค YN0000: ยท Done with warnings in 4s 123ms

Another example is the yarn config command, which sports a new tree display and now also accepts an arbitrary number of settings as positional arguments, letting you select what you wish to see:

โ”œโ”€ cacheFolder
โ”‚ โ”œโ”€ Description: Folder where the cache files must be written
โ”‚ โ”œโ”€ Source:
โ”‚ โ””โ”€ Value: '/Users/global/.yarn/berry/cache'
โ”‚
โ””โ”€ enableHardenedMode
โ”œโ”€ Description: If true, automatically enable --check-resolutions --refresh-lockfile on installs
โ”œโ”€ Source:
โ””โ”€ Value: null

Performancesโ€‹

The 4.0 isn't lagging behind in performance improvements, and shows to be significantly faster at installs than the 3.6. For instance, here's the difference in time to install Gatsby and its ~350MiB dependency tree from a cold cache. The 3x improved performances are due to a new package metadata cache which significantly improves performances of repeated installs:

hyperfine -L v stable,canary --prepare 'rm -rf ~/.yarn/berry/cache' 'cd $(mktemp -d) && yarn init -2 && yarn set version {v} && yarn && yarn add gatsby --mode=skip-build'
Benchmark 1: 3.6.0
Time (mean ยฑ ฯƒ): 65.599 s ยฑ 2.214 s [User: 82.952 s, System: 8.638 s]
Range (min โ€ฆ max): 62.167 s โ€ฆ 68.277 s 10 runs

Benchmark 2: 4.0.0
Time (mean ยฑ ฯƒ): 16.724 s ยฑ 0.928 s [User: 14.622 s, System: 5.743 s]
Range (min โ€ฆ max): 15.318 s โ€ฆ 18.110 s 10 runs

Summary
4.0.0 ran 3.92 ยฑ 0.25 times faster than 3.6.0

These changes make Yarn as fast as pnpm in most scenarios, although competition is still fierce ๐Ÿ”ฅ

Fancy Websiteโ€‹

As you probably noticed, our website received a major overhaul, both style and content! We worked on this new iteration for more than a year now, and we hope it'll help you find better information, faster than before.

Some particular improvements:

  • All referenced commands now link to their documentation (yarn install)
  • All referenced options now have a tooltip explaining their goal (yarn --immutable-cache)
  • Most pages were rewritten to be both simplified & clarified when needed
  • The package page now shows various configurable checks, like whether a package supports CJS, ESM, has types, ...

Our expertise lies in tooling more than building websites, so I'm sure various hanging fruits remain - especially around loading time. If you're interested to help us, check the sources and please feel free to send PRs our way!

Closing Wordsโ€‹

The journey to transition from Yarn 3 to Yarn 4 was a lengthy one, with a whopping 53 release candidates along the way, but we finally made it! Our aim for this new iteration has been to both decrease Yarn's learning curve and improve your user experience, without the migration feeling overwhelming. We made concerted efforts to avoid making significant breaking changes unless we also had ways to automatically migrate projects, so if you encounter any issues that you believe the software should have addressed, share your feedback with us on Discord.

As for what lies ahead, it's a bit too early to provide a definitive answer, but I can tell you I'm particularly intrigued by the potential for native Yarn builds. Performances has been under the spotlight lately, and I sometimes wonder how much overhead may have Node.js on the overall execution time. That being said, we don't plan on undertaking another complete rewrite of the codebase, nor do we want to compromise the factors that make Yarn so contributor-friendly, so the specifics, as well as the timeline, are still under consideration.

In the meantime we'll continue to build upon our existing foundations for the time being. From CLI completion and UI commands to reducing the learning curve and general upkeep, we have a broad array of improvements on our radar. So see you next time!