Refers to tasks executed right after the packages got installed; typically the
postinstall scripts configured in the
scripts field from the manifest.
See also: Lifecycle Scripts
A dependency (listed in the
dependencies field of the manifest) describes a relationship between two packages.
When a package A has a dependency B, Yarn guarantees that A will be able to access B if the install is successful. Note that this is the only promise we make regarding regular dependencies: in particular, there is no guarantee that package B will be the same version than the one used in other parts of the application.
A descriptor is a combination of a package name (for example
lodash) and a package range (for example
^1.0.0). Descriptors are used to identify a set of packages rather than one unique package.
A dependency (listed in the
devDependencies field of the manifest) describes a relationship between two packages.
Development dependencies are very much like regular dependencies except that they only matter for local packages. Packages fetched from remote registries such as npm will not be able to access their development dependencies, but packages installed from local sources (such as workspaces or the
portal: protocol) will.
Fetchers are the components tasked with extracting the full package data from a reference. For example, the npm fetcher would download the package tarballs from the npm registry.
Hoisting is the act of transforming the dependency tree to optimize it by removing as many nodes as possible. There isn't a single way to decide how to transform the tree, and different package managers make different tradeoffs (some optimize for package popularity, package size, highest versions, ...). For this reason, no guarantee can be made regarding the final hoisting layout - except that packages will always be able to access the dependencies they listed in their manifests.
Because the hoisting is heavily connected to the filesystem and the Node resolution, its very design makes it easy to make an error and accidentally access packages without them being properly defined as dependencies - and thus without being accounted for during the hoisting process, making their very existence unpredictable. For this reason and others, hoisting got sidelined starting from Yarn 2 in favour of the Plug'n'Play resolution.
Linkers are the components that consume both a dependency tree and a store of package data, and generate in return disk artifacts specific to the environment they target. For example, the Plug'n'Play linker generates a single
The local cache, or offline mirror, is a way to protect your project against the package registry going down.
When the local cache is enabled, Yarn generates a copy of all packages you install in the
.yarn/cache folder that you can then add to your repository. Subsequent installs will then reuse packages from this folder rather than downloading them anew.
While not always practical (it causes the repository size to grow, although we have ways to mitigate it significantly), it presents various interesting properties:
- It doesn't require additional infrastructure, such as a Verdaccio proxy
- It doesn't require additional configuration, such as registry authentication
- The install fetch step is as fast as it can be, with no data transfer at all
- It lets you reach zero-installs if you also use the PnP linker
A locator is a combination of a package name (for example
lodash) and a package reference (for example
1.2.3). Locators are used to identify a single unique package (interestingly, all valid locators also are valid descriptors).
Yarn provides native support for monorepos via "workspaces". It makes it easy to install the dependencies of multiple local packages by running a single install, and to connect them all together so that they don't have to be published before their changes can be reused by other parts of your project.
Packages are nodes of the dependency tree. Simply put, a package is a bundle of source code usually characterized by a
package.json at its root. Packages can define dependencies, which are other packages that need to be made available for it to work properly.
A dependency (listed in the
peerDependencies field of the manifest) describes a relationship between two packages.
Contrary to regular dependencies, a package A with a peer dependency on B doesn't guarantee that A will be able to access B - it's up to the package that depends on A to manually provide a version of B compatible with request from A. This drawback has a good side too: the package instance of B that A will access is guaranteed to be the exact same one as the one used by the ancestor of A. This matters a lot when B uses
instanceof checks or singletons.
A peer-dependent package is a package that lists peer dependencies.
See also: Virtual Packages
Plugins are a new concept introduced in Yarn 2+. Through the use of plugins, Yarn can be extended and made even more powerful - whether it's through the addition of new resolvers, fetchers, or linkers.
Plug'n'Play is an alternative installation strategy that, instead of generating the typical
See also: Plug'n'Play
A portal is a dependency that uses the
portal: protocol, pointing to a package located on the disk.
Contrary to the
link: protocol (which can point to any location but cannot have dependencies), Yarn will setup its dependency map in such a way that not only will the dependent package be able to access the file referenced through the portal, but the portal itself will also be able to access its own dependencies. Even peer dependencies!
The term project is used to encompass all the worktrees that belong to the same dependency tree.
See also: Workspaces
A range is a string that, when combined with a package name, can be used to select multiple versions of a single package. Ranges typically follow semver, but can use any of the supported Yarn protocols.
See also: Protocols
A reference is a string that, when combined with a package name, can be used to select one single version of a single package. References typically follow semver, but can use any of the supported Yarn protocols.
See also: Protocols
Resolvers are the components tasked from converting descriptors into locators, and extracting the package manifests from the package locators. For example, the npm resolver would check what versions are available on the npm registry and return all the candidates that satisfy the semver requirements, then would query the npm registry to fetch the full metadata associated with the selected resolution.
Scopes are a term linked inherited from the npm registry; they are used to describe a set of packages that all belong to the same entity. For example, all the Yarn packages related to the v2 belong to the
berry scope on the npm registry. Scopes are traditionally prefixed with the
A singleton package is a package which is instantiated a single time across the dependency tree.
While singleton packages aren't a first-class citizen, they can be easily created using peer dependencies by using one of their properties: since packages depended upon by peer dependencies are guaranteed to be the exact same instance as the one used by their direct ancestor, using peer dependencies across the entire dependency branch all the way up to the nearest workspace will ensure that a single instance of the package is ever created - making it a de-facto singleton package.
See also: Peer Dependency
A transitive dependency is a dependency of a package you depend on.
Imagine the case of
react. Your application depends on it (you listed it yourself in your manifest), so it's a direct dependency. But
react also depends on
prop-types! That makes
prop-types a transitive dependency, in that you don't directly declare it.
With Yarn PnP, most packages are kept within their zip archives rather than being unpacked on the disk. The archives are then mounted on the filesystem at runtime, and transparently accessed. The mounts are read-only so that the archives don't get corrupted if something tries to write into them.
In some cases, however, keeping the package read-only may be difficult (such as when a package lists postinstall scripts - the build steps will often need to generate build artifacts, making read-only folders impractical). For those situations, Yarn can unpack specific packages and keep them into their own individual folders. Such packages are referred to as "unplugged".
Packages are unplugged in a few scenarios:
- explicitly by setting the
- explicitly when the package set its
- implicitly when the package lists postinstall scripts
- implicitly when the package contains native files
Because peer-dependent packages effectively define an horizon of possible dependency sets rather than a single static set of dependencies, a peer-dependent package may have multiple dependency sets. When this happens, the package will need to be instantiated at least once for each such set.
Since in Node-land the JS modules are instantiated based on their path (a file is never instantiated twice for any given path), and since PnP makes it so that packages are installed only once in any given project, the only way to instantiate those packages multiple times is to give them multiple paths while still referencing to the same on-disk location. That's where virtual packages come handy.
Virtual packages are specialized instances of the peer-dependent packages that encode the set of dependencies that this particular instance should use. Each virtual package is given a unique filesystem path that ensures that the scripts it references will be instantiated with their proper dependency set.
In the past virtual packages were implemented using symlinks, but this recently changed and they are now implemented through a virtual filesystem layer. This circumvents the need to create hundreds of confusing symlinks, improving compatibility with Windows and preventing issues that would arise with third-party tools calling
Generally speaking workspaces are a Yarn features used to work on multiple projects stored within the same repository.
In the context of Yarn's vocabulary, workspaces are local packages that directly belong to a project.
A worktree is a private workspace that adds new child workspaces to the current project.
See also: Workspaces
See also: Zero-Install