---
slug: release/4.0
title: "Release: Yarn 4.0 🪄⚗️"
authors: [arcanis]
---

import {TerminalRender} from '@yarnpkg/docusaurus/src/components/TerminalRender';

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](/advanced/changelog#400).

{/* truncate */}

## 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](/features/caching#zero-installs) by default anymore.
- New projects created with `yarn init` will use [Corepack](https://nodejs.org/api/corepack.html) 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](/getting-started/qa#why-is-the-yarn-package-on-npm-still-on-1x).

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](https://nodejs.org/api/corepack.html). 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](/getting-started/install) 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:

```bash
export YARN_ENABLE_HARDENED_MODE=1
```
:::

## JavaScript Constraints

Yarn is the only package manager to implement a [constraints engine](/features/constraints). 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](https://en.wikipedia.org/wiki/Prolog#Rules_and_facts) 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](https://www.datadoghq.com/) with this framework for a couple of months now, with great success. You can also check the public [Yarn repository](https://github.com/yarnpkg/berry/blob/c3b319a8943dcc35e689ebff4051c112bfc598f5/yarn.config.cjs#L17-L43) for a practical example of the kind of rules you can enforce at the repository level, and the [newly revamped documentation](/features/constraints) 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:

import addNextTerm from './release-4.0--add-next.term.dat';

<TerminalRender content={addNextTerm}/>

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:

import configTerm from './release-4.0--config.term.dat';

<TerminalRender content={configTerm}/>

## 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'
```

```js
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
  // highlight-next-line
  Time (mean ± σ):     16.724 s ±  0.928 s    [User: 14.622 s, System: 5.743 s]
  // highlight-next-line
  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](/features/performances), 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](https://github.com/yarnpkg/berry/tree/master/packages/docusaurus) 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](https://discord.gg/yarnpkg).

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!
