Jesse A. Green / notebook

Yarn Admin & Architecture Guide

Generated June 2026 from yarnpkg/yarn at c2dda50

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

A complete, source-based reference to the internals, configuration, operations, and security model of Yarn 1 ("Classic"), version 1.23.0-0 (commit c2dda50). This guide is written for operators, build engineers, platform architects, and contributors — anyone who needs to understand how Yarn works inside rather than just how to use it. For day-to-day command usage, see the companion User Guide.


Table of Contents

  1. Executive Summary
  2. System Architecture
  3. The Install Pipeline
  4. Repository Structure
  5. Module Reference
  6. The Lockfile Format
  7. Registries & Resolution
  8. Configuration Mastery
  9. Environment Variables
  10. Caching, Mirrors & Storage
  11. Security Analysis
  12. Operations & CI
  13. Building Yarn From Source
  14. Error Model & Exit Codes
  15. Code Quality & Conventions
  16. Potential Improvements
  17. Quick Reference

1. Executive Summary

Yarn is a command-line dependency manager for the JavaScript/Node.js ecosystem. Its job is to take a declarative manifest (package.json) and produce a deterministic, verified, on-disk dependency tree (node_modules) plus a lockfile (yarn.lock) that pins the exact result.

Key facts

Property Value
Project name yarn (binaries: yarn, yarnpkg)
Version analyzed 1.23.0-0
License BSD-2-Clause
Language JavaScript (ES with Flow type annotations)
Runtime Node.js (engines.node >= 4.0.0; supported set ^4.8.0 || ^5.7.0 || ^6.2.2 || >=8.0.0)
Entry point bin/yarn.js → src/cli/index.js
Build system Gulp (Babel transpile) + Webpack (single-file bundle)
Type checking Flow
Tests Jest
Default registry https://registry.yarnpkg.com (a CDN proxy of the npm registry)
Lockfile version 1
Cache version 6

Design goals. Yarn was built to solve three problems with early npm: determinism (a lockfile that pins the whole tree), speed (a global cache + parallel network and I/O), and security (integrity hashes on every package). Those three pillars are visible throughout the architecture: the resolver produces a fully pinned graph, the fetcher caches and hashes everything, and the lockfile records both.

Note

"Classic" Yarn (the 1.x line documented here) is a mature, stable codebase in maintenance mode. The actively developed successor, Yarn 2+ ("Berry"), is a separate repository with a plugin architecture and Plug'n'Play by default. Yarn 1 already ships an experimental Plug'n'Play implementation (see §7).


2. System Architecture

Yarn is a single Node process that orchestrates several cooperating subsystems. There is no daemon, no server, and no database — state lives entirely in files (package.json, yarn.lock, the cache, and .yarnrc/.npmrc).

                         bin/yarn.js  (thin launcher; honors yarn-path)
                                │
                                ▼
                    src/cli/index.js  (main)
        ┌───────────────────────┼────────────────────────┐
        │  parse global flags (commander.js)              │
        │  resolve command name (default = "install")     │
        │  build Reporter (Console | JSON)                │
        │  construct Config  ◄─────── .yarnrc / .npmrc / env / DEFAULTS
        │  acquire mutex (optional: file | network)       │
        └───────────────────────┬────────────────────────┘
                                │ command.run(config, reporter, flags, args)
                                ▼
                  src/cli/commands/<command>.js   (44 commands)
                                │
        ┌───────────────┬───────┴────────┬───────────────┬──────────────┐
        ▼               ▼                ▼               ▼              ▼
  PackageResolver  PackageFetcher  PackageLinker  PackageHoister  PackageInstallScripts
        │               │                │               │              │
        ▼               ▼                ▼               ▼              ▼
   Resolvers       Fetchers         node_modules     hoisted tree   lifecycle scripts
  (registry +     (tarball/git/         layout
   8 exotics)      copy + cache)
        │               │
        ▼               ▼
    Registries      Global cache + offline mirror
  (npm + yarn)
        │
        ▼
   RequestManager  (HTTP, retries, concurrency, HAR capture)

Layering

Layer Responsibility Key modules
CLI Argument parsing, command dispatch, output src/cli/index.js, src/cli/commands/*
Orchestration The install lifecycle and its steps src/cli/commands/install.js (the Install class)
Resolution Turn version ranges into pinned packages src/package-resolver.js, src/resolvers/*
Fetching Download + cache + verify packages src/package-fetcher.js, src/fetchers/*
Linking Lay out node_modules, hoist, link bins src/package-linker.js, src/package-hoister.js
Registry I/O Auth, config, registry protocol src/registries/*, src/util/request-manager.js
Persistence Lockfile + integrity src/lockfile/*, src/integrity-checker.js
Reporting Console/JSON output, progress, prompts src/reporters/*
Config Merge .yarnrc/.npmrc/env/defaults src/config.js, src/rc.js

The launcher and yarn-path

src/cli/index.js's start() function checks for a yarn-path (or yarnPath) setting in the resolved .yarnrc. If present — and the YARN_IGNORE_PATH environment variable is not set — Yarn spawns the Yarn bundle at that path instead of running itself. This is the mechanism behind yarn policies set-version / yarn set version: a project can commit an exact Yarn release into .yarn/releases/ and pin every developer to it regardless of their globally installed Yarn.

process start
   │
   ├─ read .yarnrc for yarn-path
   │     └─ if set and !YARN_IGNORE_PATH → spawn that bundle (.cjs via node, else direct) → exit
   │
   └─ otherwise → main({startArgs, args, endArgs})

3. The Install Pipeline

The Install class in src/cli/commands/install.js (≈1,150 lines) is the heart of Yarn. yarn add, yarn remove, yarn upgrade, yarn import, yarn unplug, yarn check, yarn list, and others all subclass or reuse it.

Install.init() assembles an ordered list of steps, each wrapped in a hook (callThroughHook) so plugins/experimentalYarnHooks can intercept them, then runs them in sequence with progress reporting:

Install.init()
  ├─ checkUpdate()                 once-a-day self-update nag
  ├─ fetchRequestFromCwd()         read manifests → dependency requests + patterns
  ├─ (optional) checkCompatibility  engines/os/cpu checks
  ├─ STEP resolveStep   → resolver.init(requests)        Resolving packages...
  │        └─ bailout() if integrity matches and lockfile is clean → done early
  ├─ STEP auditStep     → audit.performAudit() (if --audit)        Auditing...
  ├─ STEP fetchStep     → fetcher.fetch(manifests)                 Fetching packages...
  │        └─ compatibility.check() across the whole graph
  ├─ STEP linkStep      → linker.init(patterns)                    Linking dependencies...
  ├─ STEP pnpStep       → generatePnpMap() (if PnP enabled)        write .pnp.js
  ├─ STEP buildStep     → scripts.init() (unless --ignore-scripts) Building fresh packages...
  ├─ (optional) HAR save / autoclean
  ├─ saveLockfileAndIntegrity()    write yarn.lock + .yarn-integrity
  └─ persistChanges()              write back package.json (for add/remove/upgrade)

The bailout optimization

Before doing any network work, Install.bailout() consults the integrity checker (src/integrity-checker.js). It compares the requested patterns, the lockfile cache, the flags, and the workspace layout against the stored .yarn-integrity file. If everything matches and a lockfile exists, Yarn prints success Already up-to-date. and exits immediately. This is why a no-op yarn install is nearly instantaneous.

Bailout is disabled when --audit, --force, --skip-integrity-check, or Plug'n'Play is in effect (PnP installs are fast enough that the check is not worthwhile). --frozen-lockfile additionally turns a needed-update into a hard error here.

Lifecycle script ordering

wrapLifecycle() (exported from install.js) frames the install with npm-compatible lifecycle scripts:

preinstall → [install work] → install → postinstall → (if !production) prepublish → prepare

yarn run adds pre<script>/post<script> wrapping for arbitrary scripts; yarn publish runs prepublish, prepare, prepublishOnly, prepack, then publish, postpublish; yarn pack runs prepack/postpack; yarn remove runs preuninstall/uninstall/postuninstall.


4. Repository Structure

The repository is large by file count (~5,200 files) but the source is concentrated — most files are test fixtures and a cached HTTP request fixture set under __tests__/fixtures/request-cache/. The triage that matters:

yarn/
├── bin/                        Launcher scripts (yarn.js)
├── src/                        ◄── ALL production source
│   ├── cli/
│   │   ├── index.js            main(): flag parsing, dispatch, mutex, error handling
│   │   ├── aliases.js          command-name aliases (upgrade-interactive, etc.)
│   │   └── commands/           44 command modules (see §5)
│   ├── registries/             npm + yarn registry clients
│   ├── resolvers/              registry resolvers + 8 exotic resolvers
│   ├── fetchers/               tarball / git / copy fetchers
│   ├── lockfile/               lockfile parse / stringify
│   ├── reporters/              console / json / buffer / event reporters
│   │   └── lang/               localized message strings (en.js, ...)
│   ├── util/                   ~40 utility modules (fs, git, crypto, ...)
│   │   └── normalize-manifest/ package.json normalization + validation
│   ├── config.js               central configuration object
│   ├── constants.js            URLs, filenames, versions, concurrency
│   ├── errors.js               error class hierarchy
│   ├── package-resolver.js     drives resolution of the whole graph
│   ├── package-fetcher.js      drives fetching of all manifests
│   ├── package-linker.js       lays out node_modules + bin links
│   ├── package-hoister.js      hoisting / deduplication algorithm
│   ├── package-request.js      a single dependency request
│   ├── package-reference.js    a resolved package reference
│   ├── package-install-scripts.js  runs install/build scripts in parallel
│   ├── package-compatibility.js    engines/os/cpu checks
│   ├── integrity-checker.js    decides whether reinstall is needed
│   ├── workspace-layout.js     workspace graph model
│   ├── resolution-map.js       selective "resolutions" field support
│   └── hoisted-tree-builder.js builds the tree audit/why/list consume
├── packages/
│   ├── lockfile/               @yarnpkg/lockfile (standalone parser package)
│   └── pkg-tests/              end-to-end behavioral test harness
├── __tests__/                  Jest unit tests + fixtures
├── scripts/                    build/release scripts (dist, deb, rpm, chocolatey, win)
├── resources/                  installer resources (debian, winsetup, chocolatey)
└── package.json                manifest (deps, scripts, jest config)

5. Module Reference

CLI commands (src/cli/commands/, 44 modules)

Each command module exports run, setFlags, and hasWrapper, and is registered in src/cli/commands/index.js. The dispatcher in index.js defaults to install when no command is given, and to run (script execution) when an unrecognized name is given.

Install family (subclass or reuse the Install class):

Module Command Notes
install.js install The base Install class + the install pipeline.
add.js add Add extends Install; appends args as new requests, computes save ranges.
remove.js remove Deletes from manifest + reinstalls to regenerate the lockfile.
upgrade.js upgrade Computes outdated set, unlocks them in the lockfile, delegates to Add.
upgrade-interactive.js upgrade-interactive Inquirer checkbox UI over the outdated set.
import.js import Import extends Install; builds a graph from package-lock.json/node_modules.
unplug.js unplug Marks packages for unplugging during a PnP install.
check.js check Verifies tree vs. lockfile (--integrity, --verify-tree).
list.js list Builds and prints the hoisted tree.
outdated.js outdated Diffs current vs. wanted vs. latest.
licenses.js licenses list + generate-disclaimer subcommands.
audit.js audit Posts a gzip'd dependency tree to the registry audit endpoint.
why.js why Traces dependency reasons and disk sizes.

Project & scripts:

Module Command Notes
init.js init Interactive manifest creation; -2/--install delegate to policies set-version.
run.js run Runs package.json scripts and .bin binaries; suggests on typos via leven.
exec.js exec Runs an arbitrary command in Yarn's env.
node.js node Runs Node with Yarn's version + PnP require.
bin.js bin Prints .bin folder or a binary path.
create.js create Global-installs and runs a create-* package.

Registry / publishing:

Module Command Notes
publish.js publish Bump → login → pack → PUT to registry → revoke token.
pack.js pack Builds the publishable tarball (honors files, .npmignore, bundledDependencies).
version.js version Bumps version, runs preversion/version/postversion, git-tags.
versions.js versions Reports yarn/node/component versions.
login.js / logout.js login/logout Store/clear registry credentials; token acquisition (getToken).
owner.js owner Add/remove/list package maintainers.
tag.js tag Manage dist-tags.
team.js team Manage org teams.
info.js info Registry metadata for a package.
access.js access Reserved — notYetImplemented.
generate-lock-entry.js generate-lock-entry Print a lockfile entry for the current package.

Global / linking / workspaces / config:

Module Command Notes
global.js global add/remove/list/upgrade/bin/dir; manages a side install + bin links.
link.js / unlink.js link/unlink Create/remove dev symlinks in the global link registry.
workspace.js workspace Run a command in one named workspace.
workspaces.js workspaces info + run across all workspaces.
config.js config get/set/delete/list/current against .yarnrc.
policies.js policies set-version Download + pin a Yarn release (incl. berry, nightly).
cache.js cache list/dir/clean on the global cache.
autoclean.js autoclean Strip docs/tests/examples from deps via .yarnclean.
help.js help Render help text.

Helper modules: _build-sub-commands.js (factory for commands with subcommands like cache, config, global), _useless.js (factory for the deliberate no-op commands).

Note

Three commands are intentional no-ops built via _useless.js: dedupe, prune, and lockfile. Each throws a message explaining that yarn install already performs the operation. This is documented behavior, not a bug.

Core engine modules (src/)

Module Role
package-resolver.js Orchestrates resolution of the entire graph; deduplicates patterns; tracks patterns/patternsByPackage; integrates ResolutionMap.
package-request.js Represents one dependency request; finds versions on the registry or via exotic resolvers; computes the outdated set (getOutdatedPackages).
package-reference.js A resolved package instance with its requests, patterns, remote, permissions.
package-fetcher.js Fetches all resolved manifests (parallel), populating the cache.
package-linker.js Builds the flat hoisted tree, copies/symlinks packages, links bins, resolves peer dependencies.
package-hoister.js The hoisting algorithm; HoistManifest, NohoistResolver for nohoist workspace rules.
package-install-scripts.js Runs install/postinstall build scripts with bounded concurrency.
package-compatibility.js Validates engines, os, cpu against the host.
integrity-checker.js Computes/compares .yarn-integrity; the basis of the bailout optimization.
resolution-map.js Implements the resolutions manifest field for forcing transitive versions.
workspace-layout.js Models the workspace graph and the virtual aggregator manifest.
config.js The central Config object: folders, registries, options, lifecycle script execution, manifest read/write.
lockfile/ Custom lockfile tokenizer/parser + stringifier (see §6).

6. The Lockfile Format

yarn.lock (lockfile version 1) is generated by src/lockfile/stringify.js and read by src/lockfile/parse.js. It is a custom, YAML-like, human-readable format — not JSON and not strictly YAML.

A representative entry:

# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


lodash@^4.17.0, lodash@^4.17.21:
  version "4.17.21"
  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#hash"
  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvKw==

Key properties of the format:

  • Multiple patterns share one entry. lodash@^4.17.0, lodash@^4.17.21: means both ranges resolved to the same package; the body is written once.
  • Field ordering is stable. stringify.js sorts fields by a fixed priority (name, version, uid, resolved, integrity, registry, dependencies) then alphabetically, so diffs stay minimal across runs.
  • Keys are quoted only when necessary (maybeWrap/shouldWrapKey), keeping the file readable.
  • npm registry is the implicit default — entries omit registry when it is npm (implodeEntry).
  • Integrity is normalized with a stable sort of multi-hash strings (serializeIntegrity).

The parser

parse.js implements a hand-written tokenizer (tokenise) and recursive-descent Parser. Notable behaviors:

  • It enforces two-space indentation — odd indentation throws Invalid number of spaces.
  • It rejects newer lockfiles: if a # yarn lockfile v<N> comment declares a version greater than LOCKFILE_VERSION (1), it errors and tells you to upgrade Yarn.
  • If the custom parse fails on a non-.yml file, it falls back to a YAML safe-load (js-yaml FAILSAFE_SCHEMA).
  • It detects and resolves git merge conflicts automatically: hasMergeConflicts() finds <<<<<<</=======/>>>>>>> markers, extractConflictVariants() splits the two sides, and both are parsed and merged. A successful merge reports info Merge conflict detected in yarn.lock and successfully merged.; an unmergeable one returns a conflict result.

Tip

Because Yarn auto-merges lockfile conflicts, the recommended resolution for a yarn.lock git conflict is simply to run yarn install — it will parse both variants, merge them, and rewrite a clean lockfile.

The standalone @yarnpkg/lockfile package (packages/lockfile/) exposes this parse/stringify pair for third-party tooling.


7. Registries & Resolution

Dual-registry model

src/registries/ defines two registry clients, both subclasses of BaseRegistry:

BaseRegistry
  └─ NpmRegistry      (folder: node_modules; filename: package.json)
        └─ YarnRegistry  (filename: yarn.json; holds Yarn's own defaults + ~/.yarnrc)
  • NpmRegistry speaks the npm registry protocol: it resolves the registry URL per package/scope, handles scoped-package name escaping (@scope%2fpkg), enforces HTTPS for yarnpkg.com/npmjs.org, reads .npmrc from the standard cascade (cwd → home → global prefix etc), and assembles auth headers (_authToken → Bearer, _auth → Basic, username/_password → Basic). It also handles 2FA: on a OneTimePasswordError it prompts for a one-time password and retries.
  • YarnRegistry layers Yarn-specific defaults on top. Its DEFAULTS object is the authoritative source of Yarn's built-in configuration values (see §8). Its getOption() resolves a key by checking the Yarn config, then an npm-name mapping (npmMap), then the npm config, then DEFAULTS. It persists global settings to ~/.yarnrc via saveHomeConfig().

Resolvers

src/resolvers/index.js registers two registry resolvers (npm, yarn) and eight exotic resolvers for non-registry sources. getExoticResolver(pattern) tests each in turn:

Exotic resolver Pattern example
git-resolver git+https://…, git+ssh://…
tarball-resolver https://example.com/pkg.tgz
github-resolver user/repo, github:user/repo
gitlab-resolver gitlab:user/repo
bitbucket-resolver bitbucket:user/repo
gist-resolver gist:hash
file-resolver file:../path
link-resolver link:../path

Each registry resolver is also exposed as an exotic via a generated ExoticRegistryResolver subclass, enabling npm:foo@1.0.0 / yarn:foo@1.0.0 protocol patterns.

Fetchers

src/fetchers/ mirrors the resolver families. BaseFetcher.fetch() creates the destination, calls the subclass _fetch(), normalizes the resulting manifest, and links any declared bin entries (via cmd-shim on Windows, symlinks elsewhere). Subclasses include a tarball fetcher (with a LocalTarballFetcher), a git fetcher, and a copy fetcher for file: dependencies. Fetched tarballs may be copied into the offline mirror for air-gapped reinstalls.

Plug'n'Play (experimental)

When --enable-pnp/--pnp is set (or installConfig.pnp in package.json), the install pipeline adds a pnpStep that writes a .pnp.js file mapping every dependency to its location in the cache, bypassing node_modules entirely. yarn node and yarn run auto---require this file. yarn unplug materializes a package out of the cache into .yarn/unplugged/ for debugging; it errors if PnP is disabled.


8. Configuration Mastery

Configuration sources & precedence

Yarn merges configuration from multiple sources. Highest precedence wins:

command-line flags
  ▼
environment variables (YARN_*, NPM_CONFIG_*, npm_config_*)
  ▼
project .yarnrc / .npmrc   (searched cwd → upward)
  ▼
home  ~/.yarnrc / ~/.npmrc
  ▼
global prefix  etc/yarnrc / etc/npmrc
  ▼
YarnRegistry.DEFAULTS  (built-in defaults)

.yarnrc is parsed with the lockfile parser; .npmrc is parsed as INI (ini). Disable auto-detection with --no-default-rc; supply an explicit file with --use-yarnrc <path>.

Built-in defaults (YarnRegistry.DEFAULTS)

These are the authoritative Yarn defaults from src/registries/yarn-registry.js:

Key Default Meaning
registry https://registry.yarnpkg.com Package registry.
save-prefix ^ Range prefix for yarn add.
bin-links true Create .bin symlinks.
ignore-scripts false Skip lifecycle scripts.
ignore-optional false Skip optional dependencies.
strict-ssl true Enforce valid TLS certs.
init-version 1.0.0 Default version for yarn init.
init-license MIT Default license for yarn init.
version-tag-prefix v Git tag prefix for yarn version.
version-git-tag true Create a git tag on yarn version.
version-git-sign false GPG-sign the version tag.
version-commit-hooks true Run git commit hooks.
version-git-message v%s Version commit message template.
user-agent yarn/<v> npm/? node/<v> <platform> <arch> HTTP User-Agent.

npm-key compatibility mapping

YarnRegistry maps several Yarn config names to their npm equivalents (npmMap), so npm config files keep working:

Yarn key npm key
version-git-sign sign-git-tag
version-tag-prefix tag-version-prefix
version-git-tag git-tag-version
version-commit-hooks commit-hooks
version-git-message message

Path-relative keys

These keys are resolved relative to the .yarnrc that defines them, and folder keys are auto-created: yarn-offline-mirror, cache-folder, global-folder, offline-cache-folder, yarn-path.

Other notable settings

Setting Effect
yarn-path Spawn a pinned Yarn bundle instead of the global one.
yarn-offline-mirror Directory to mirror downloaded tarballs into.
yarn-offline-mirror-pruning Prune unused tarballs from the mirror on install.
disable-self-update-check Suppress the once-a-day outdated-Yarn nag.
script-shell Shell used to run scripts.
scripts-prepend-node-path Prepend Node's dir to PATH in scripts.
lastUpdateCheck Timestamp Yarn writes to throttle update checks.

Important

Yarn reads both Yarn-prefixed (YARN_*) and npm-prefixed (NPM_CONFIG_*, npm_config_*) environment variables. Environment variables are converted to config keys by lowercasing, stripping the prefix, turning __ into . and _ into -. This is how CI systems inject registry tokens (npm_config_//registry.example.com/:_authToken).


9. Environment Variables

Yarn reads these process environment variables directly (from src/constants.js, src/config.js, registry, and command modules):

Variable Used for
YARN_SILENT Force silent mode (equivalent to --silent).
YARN_IGNORE_PATH Ignore the yarn-path setting (prevents launcher recursion).
YARN_WRAP_OUTPUT Toggle the header/footer output wrapper.
YARN_AUTH_TOKEN / NPM_AUTH_TOKEN Bearer token for registry auth (yarn login/getToken).
NPM_CONFIG_* / npm_config_* npm-style config injection (registry, auth, etc.).
NODE_ENV / NPM_CONFIG_PRODUCTION / YARN_PRODUCTION Toggle production (skip devDependencies).
CHILD_CONCURRENCY Override max concurrent child processes (default 5).
NODE_OPTIONS Passed through to yarn node.
PREFIX / DESTDIR / LOCALAPPDATA Global install prefix resolution.
GITHUB_TOKEN Authenticated GitHub API calls in policies set-version.
HOME / USERPROFILE / XDG_* Home, cache, config, and data directory resolution.
TERM_PROGRAM Emoji auto-enable detection.
PATH / Path Binary lookup (platform-aware key via getPathKey).

10. Caching, Mirrors & Storage

Yarn keeps three distinct on-disk stores. Their locations are platform-dependent and derived in src/constants.js + src/util/user-dirs.js (XDG on Linux, AppData on Windows, etc.).

Store Constant / setting Purpose
Global cache PREFERRED_MODULE_CACHE_DIRECTORIES (XDG cache dir, then os.tmpdir()/.yarn-cache-<uid>) Every downloaded + extracted package, keyed by integrity. Cache format version 6.
Link registry LINK_REGISTRY_DIRECTORY (<dataDir>/link) Symlinks created by yarn link.
Global modules GLOBAL_MODULE_DIRECTORY (<dataDir>/global) Packages installed via yarn global add.
Offline mirror yarn-offline-mirror (opt-in) Raw .tgz tarballs kept next to the project for offline installs.

Inspect and manage the cache:

yarn cache dir                # print cache location
yarn cache list               # list cached packages
yarn cache list --pattern lo* # filter by name
yarn cache clean              # wipe the whole cache
yarn cache clean lodash       # remove one package

Tip

On CI, persist the global cache (yarn cache dir) across builds rather than node_modules. Combined with --frozen-lockfile, this gives fast, fully reproducible installs. For air-gapped builds, commit a yarn-offline-mirror and install with --offline.

Yarn-managed sentinel files inside a project:

File Purpose
yarn.lock The lockfile.
.yarn-integrity Integrity snapshot powering the bailout optimization.
.yarnclean Filter list for yarn autoclean.
.pnp.js Plug'n'Play resolution map (when PnP enabled).
.yarn-single-instance Mutex lock file (--mutex file).
yarn-error.log Crash report written on unexpected errors.

11. Security Analysis

Integrity verification

Every fetched package is verified against a cryptographic integrity hash (Subresource-Integrity style, sha512 preferred with sha1 fallback via the ssri library). The hash is recorded in yarn.lock (integrity field) and in .yarn-integrity. A package whose downloaded bytes do not match its recorded hash is rejected. This protects against tampered mirrors and corrupted downloads.

Transport security

NpmRegistry enforces HTTPS for the official registries: any http:// URL matching yarnpkg.com, npmjs.org, or npmjs.com is rewritten to https:// (REGEX_REGISTRY_ENFORCED_HTTPS). TLS certificate validation is on by default (strict-ssl: true). Proxies are supported via --proxy/--https-proxy.

Authentication

Credentials are never hard-coded. Auth is resolved per-registry from config in priority order: _authToken (Bearer) → _auth (Basic) → username + _password (Basic). Tokens can also come from YARN_AUTH_TOKEN/NPM_AUTH_TOKEN env vars. Two-factor auth is supported interactively or via --otp. yarn login stores only username/email in ~/.yarnrc; the password is requested per publish and used to mint a token that is revoked at the end of the operation (see publish/owner/tag/team flows).

Lifecycle script execution (the main risk surface)

Like all package managers, Yarn's largest attack surface is install scripts (preinstall/install/postinstall) — arbitrary code that runs during install. Mitigations available to operators:

  • --ignore-scripts (or ignore-scripts: true in config) disables all lifecycle scripts.
  • yarn audit (and --audit during install) flags known-vulnerable packages against the registry advisory database.
  • The integrity system ensures the bytes of a package match what was locked, so a malicious change to an already-locked package is detected.

Caution

Running yarn install executes install scripts from every dependency in the tree by default. In untrusted or high-security environments, install with --ignore-scripts and audit scripts before enabling them. Pair this with a committed yarn.lock so the exact, reviewed package set is what gets installed.

Error classes with security meaning

src/errors.js defines SecurityError (a MessageError subclass) and OneTimePasswordError, used to surface integrity/auth failures distinctly from ordinary errors.

Note

Yarn 1 depends on the now-deprecated request HTTP library and uses the legacy url.parse API (the source of the Node 24 deprecation warning, community issue #9210). These are maintenance/compatibility concerns rather than active vulnerabilities, but they are reasons the project recommends migrating to Yarn 2+ for new work.


12. Operations & CI

yarn install --frozen-lockfile --non-interactive
  • --frozen-lockfile fails the build if yarn.lock is out of date — catching un-committed dependency changes.
  • --non-interactive prevents Yarn from ever blocking on a prompt (it would otherwise error Can't answer a question unless a user TTY).

Deployment

yarn install --frozen-lockfile --production

Installs only runtime dependencies. Combine with NODE_ENV=production for the same effect via environment.

Concurrency tuning

Knob Default How to change
Network concurrency 8 --network-concurrency <n>
Network timeout 30000 ms --network-timeout <ms>
Child-process concurrency 5 CHILD_CONCURRENCY env var

Single-instance enforcement

yarn install --mutex file              # lock via .yarn-single-instance
yarn install --mutex network:31997     # lock via a localhost port

Useful when multiple jobs might run Yarn in the same workspace concurrently. The default single-instance port is 31997.

Diagnostics

Action Command
Verbose internals yarn <cmd> --verbose
Machine-readable logs yarn <cmd> --json
Network capture yarn install --har → yarn-install_<ts>.har
Verify install integrity yarn check / yarn check --integrity
Crash report auto-written to yarn-error.log (includes args, env PATH, versions, manifests, lockfile)

Tip

When filing a bug, attach the auto-generated yarn-error.log. It captures the command arguments, Yarn/Node versions, platform, full stack trace, and the relevant manifests and lockfile — everything a maintainer needs to reproduce.

Pinning Yarn for the whole team

yarn policies set-version 1.22.19   # or: latest, rc, nightly, berry

This writes .yarn/releases/yarn-<v>.cjs and sets yarn-path in .yarnrc. Commit both. Every subsequent yarn invocation in the repo runs that exact bundle, regardless of each developer's globally installed version.


13. Building Yarn From Source

Yarn is written in Flow-typed JavaScript and transpiled with Babel via Gulp; release artifacts are bundled with Webpack.

Key package.json scripts:

Script Command Purpose
build gulp build Transpile src/ → lib/.
build-bundle node ./scripts/build-webpack.js Single-file Webpack bundle.
build-dist bash ./scripts/build-dist.sh Full distributable build.
build-deb ./scripts/build-deb.sh Debian package.
build-chocolatey powershell ./scripts/build-chocolatey.ps1 Windows Chocolatey package.
build-win-installer scripts\build-windows-installer.bat Windows MSI.
watch gulp watch Rebuild on change.
lint eslint . && flow check Lint + type-check.
test yarn lint && yarn test-only Full test suite.
test-only node --max_old_space_size=4096 node_modules/jest/bin/jest.js --verbose Jest only.

Testing:

  • Unit tests live in __tests__/, run by Jest, and use a committed HTTP request cache (__tests__/fixtures/request-cache/) so tests run offline and deterministically.
  • End-to-end tests live in packages/pkg-tests/ and exercise real install behavior against fixture packages.

CI matrices (AppVeyor / Azure Pipelines) test across Node 8/10/12/13 on Windows, Linux, and macOS.

Note

Yarn is self-hosting: its own CI uses Yarn to install Yarn's dependencies (yarn install --frozen-lockfile), and the development bootstrap script adds the Yarn apt repository to install Yarn before building it.


14. Error Model & Exit Codes

Error class hierarchy (src/errors.js)

Error
 ├─ MessageError(msg, code)          user-facing message; printed without a stack trace
 │   ├─ ProcessSpawnError(.process)  failed to spawn a child process
 │   ├─ SecurityError                integrity / security failures
 │   └─ ProcessTermError(.EXIT_CODE) a child process terminated; carries its exit code
 ├─ ResponseError(.responseCode)     HTTP-level error
 └─ OneTimePasswordError             2FA OTP required/incorrect

MessageErrors are printed as clean one-line errors. Any other (unexpected) error triggers onUnexpectedError(), which writes a detailed yarn-error.log and prints a "report this" message. A ProcessTermError propagates the child's own exit code.

Audit exit codes

yarn audit returns a bitmask summing the severities present, so CI can gate on it:

Severity Bit value
info 1
low 2
moderate 4
high 8
critical 16

A clean audit exits 0; an audit finding a high + a low vulnerability exits 10 (8 + 2).


15. Code Quality & Conventions

Aspect Convention
Types Flow (/* @flow */ header required by lint rule flowtype/require-valid-file-annotation).
Formatting Prettier — single quotes, trailing commas, no bracket spacing, 120-col print width.
Linting ESLint extending eslint-config-fb-strict, plus a custom eslint-plugin-yarn-internal (e.g. warn-language to keep user-facing strings centralized).
require-await, no-process-exit, no-return-await Enforced as errors.
i18n All user-facing text flows through reporter.lang(key, ...args), resolved from src/reporters/lang/*. New strings must be added there, not inlined.
Command shape Every command exports run, setFlags, hasWrapper; optional examples, requireLockfile, noArguments, shouldRunInCurrentCwd.
Subcommands Built with the _build-sub-commands.js factory for a consistent yarn <cmd> <subcmd> UX.

Architecture patterns worth noting:

  • Class inheritance for command variants. Add, GlobalAdd, Import extend Install, overriding hooks (prepareRequests, bailout, applyChanges) rather than duplicating the pipeline.
  • Step-and-hook pipeline. The install flow is a list of hookable async steps, enabling experimentalYarnHooks interception (resolveStep, fetchStep, linkStep, buildStep, pnpStep, auditStep, runScript).
  • Reporter abstraction. All output goes through a Reporter interface (ConsoleReporter, JSONReporter, BufferReporter, EventReporter, NoopReporter), so --json and silent modes work uniformly and commands can be driven programmatically.

16. Potential Improvements

Observations drawn from the source (Yarn 1 is in maintenance mode, so these are largely addressed in Yarn 2+):

  • Deprecated HTTP stack. Yarn 1 depends on the unmaintained request library and legacy url.parse, producing deprecation warnings on modern Node (community issue #9210). A migration to fetch/undici would remove these.
  • Audit endpoint coupling. yarn audit assumes the registry implements the npm audit API; custom registries return 410 and break it (community issue #9234). A graceful "audit unsupported" path would improve robustness. Note the source already disables the (npm-incompatible) automatic-fix action reporting.
  • PnP is experimental in 1.x. The Plug'n'Play implementation works but is not the default; Yarn 2+ promotes it to a first-class strategy.
  • node_modules copying cost. The default linker copies packages into node_modules; --link-duplicates hard-links duplicates, but the broader inefficiency is what PnP and Yarn 2+ address.
  • Self-update nag. The once-a-day "Yarn is outdated" check writes lastUpdateCheck to home config; centrally managed installs should set disable-self-update-check.

17. Quick Reference

Key paths & files

Path Role
bin/yarn.js Launcher.
src/cli/index.js main() — parse, dispatch, run.
src/cli/commands/ 44 command modules.
src/config.js / src/constants.js Central config / canonical constants.
src/registries/yarn-registry.js Built-in config defaults.
src/lockfile/ Lockfile parse/stringify.
yarn.lock The lockfile (v1).
.yarn-integrity Bailout integrity snapshot.
yarn-error.log Crash report.

Canonical constants (src/constants.js)

Constant Value
YARN_REGISTRY https://registry.yarnpkg.com
SUPPORTED_NODE_VERSIONS ^4.8.0 || ^5.7.0 || ^6.2.2 || >=8.0.0
LOCKFILE_VERSION 1
CACHE_VERSION 6
NETWORK_CONCURRENCY 8
NETWORK_TIMEOUT 30000 ms
CHILD_CONCURRENCY 5
SINGLE_INSTANCE_PORT 31997
LOCKFILE_FILENAME yarn.lock
INTEGRITY_FILENAME .yarn-integrity
CLEAN_FILENAME .yarnclean
PNP_FILENAME .pnp.js

CI one-liners

# Reproducible install
yarn install --frozen-lockfile --non-interactive

# Production deploy
yarn install --frozen-lockfile --production

# Security gate (fails on high+ severity)
yarn audit --level high

# Offline / air-gapped
yarn install --offline

Install-pipeline cheat sheet

resolve → fetch → link → (pnp) → build → write lockfile + integrity → persist manifest
   │         │       │              │
 bailout   cache   hoist        scripts