Yarn Berry
Yarn Berry (v2+) with Plug'n'Play, zero-installs, constraints, and workspace management
You are an expert in Yarn Berry (Yarn v2 and above), including its Plug'n'Play resolution, zero-install strategy, constraints system, and workspace management. ## Key Points - Massive `node_modules` directories - Hoisting ambiguity and phantom dependencies - Slow install times from file I/O - **pnp** (default): Full Plug'n'Play with zip archives - **pnpm**: pnpm-style symlinked `node_modules` - **node-modules**: Traditional flat `node_modules` (compatibility fallback) - path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs - uses: actions/checkout@v4 - run: yarn install --immutable - uses: actions/setup-node@v4 - run: yarn install --immutable - Use PnP as the default `nodeLinker`. Only fall back to `node-modules` if a critical tool is truly incompatible. ## Quick Example ```bash yarn constraints yarn constraints --fix ``` ```yaml # .yarnrc.yml enableNetwork: false # Fail if anything needs fetching checksumBehavior: throw # Fail on checksum mismatch ```
skilldb get package-management-skills/Yarn BerryFull skill: 285 linesYarn Berry — Package Management
You are an expert in Yarn Berry (Yarn v2 and above), including its Plug'n'Play resolution, zero-install strategy, constraints system, and workspace management.
Core Philosophy
Overview
Yarn Berry is the modern rewrite of Yarn (v2+). It replaces node_modules with Plug'n'Play (PnP), a system that maps packages to zip archives and resolves them through a generated .pnp.cjs file. Combined with zero-installs (committing the dependency cache), teams can clone and run projects without an install step.
Core Concepts
Plug'n'Play (PnP)
Instead of extracting packages into a node_modules tree, PnP stores dependencies as compressed .zip files in .yarn/cache/ and generates a .pnp.cjs manifest that tells Node.js exactly where every package lives. This eliminates:
- Massive
node_modulesdirectories - Hoisting ambiguity and phantom dependencies
- Slow install times from file I/O
Zero-Installs
By committing .yarn/cache/ and .pnp.cjs to source control, team members can git clone and immediately run the project — no yarn install step required.
nodeLinker Modes
Yarn Berry supports multiple linking strategies:
- pnp (default): Full Plug'n'Play with zip archives
- pnpm: pnpm-style symlinked
node_modules - node-modules: Traditional flat
node_modules(compatibility fallback)
Release Line
Yarn Berry uses a per-project binary checked into .yarn/releases/. The global yarn command (via corepack) delegates to this local version.
Implementation Patterns
Project Setup
# Initialize with corepack
corepack enable
corepack use yarn@4
# Creates .yarnrc.yml and .yarn/ directory
yarn init -2
.yarnrc.yml Configuration
nodeLinker: pnp
# Enable global cache sharing
enableGlobalCache: false
# TypeScript plugin for automatic @types/* resolution
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
spec: "@yarnpkg/plugin-typescript"
# Patch compatibility
packageExtensions:
"react-dom@*":
peerDependencies:
react: "*"
.gitignore for Zero-Installs
# Zero-install: commit cache and PnP manifest
.yarn/*
!.yarn/cache
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
For non-zero-install (.yarn/cache not committed):
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.pnp.*
Workspace Configuration
// package.json (root)
{
"name": "my-monorepo",
"private": true,
"workspaces": [
"packages/*",
"apps/*"
]
}
Workspace Commands
# Run a script in a specific workspace
yarn workspace @myorg/web build
# Run across all workspaces
yarn workspaces foreach -A run build
# Topological order (dependencies first)
yarn workspaces foreach -At run build
# Parallel execution
yarn workspaces foreach -Ap run lint
# Only changed workspaces (since main)
yarn workspaces foreach -A --since=main run test
# Add dependency to a workspace
yarn workspace @myorg/web add react
# Add workspace sibling
yarn workspace @myorg/web add @myorg/shared
PnP and Editor SDKs
Many editors need SDK support to resolve PnP packages. Install the SDKs:
yarn dlx @yarnpkg/sdks vscode
# This creates .yarn/sdks/ with settings for:
# - TypeScript
# - ESLint
# - Prettier
For VS Code, add to .vscode/settings.json:
{
"typescript.tsdk": ".yarn/sdks/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"search.exclude": {
"**/.yarn": true,
"**/.pnp.*": true
}
}
Patching Dependencies
# Create a patch for a broken dependency
yarn patch lodash
# Edit files in the temporary directory it opens, then:
yarn patch-commit -s path/to/patched/lodash
# The patch is stored in .yarn/patches/ and applied on install
Constraints (Programmatic Policy Enforcement)
Create constraints.pro (Prolog) or yarn.config.cjs (JS) to enforce workspace rules:
// yarn.config.cjs
module.exports = {
async constraints({ Yarn }) {
// All workspaces must have a license
for (const workspace of Yarn.workspaces()) {
workspace.set('license', 'MIT');
}
// Enforce consistent dependency versions
for (const dep of Yarn.dependencies()) {
if (dep.ident === 'typescript') {
dep.update('^5.5.0');
}
}
// All workspaces must have a build script
for (const workspace of Yarn.workspaces()) {
if (workspace.ident !== 'my-monorepo') {
workspace.set('scripts.build', expect.stringMatching(/.+/));
}
}
}
};
yarn constraints
yarn constraints --fix
Protocols
{
"dependencies": {
"@myorg/shared": "workspace:^",
"lodash": "npm:4.17.21",
"my-fork": "git@github.com:me/lodash.git#commit=abc123",
"local-tool": "portal:../local-tool",
"patched-lib": "patch:left-pad@1.3.0#.yarn/patches/left-pad-npm-1.3.0-abc123.patch"
}
}
CI Configuration
# GitHub Actions
- uses: actions/checkout@v4
# For zero-installs, no install step needed. Just verify:
- run: yarn install --immutable
# For non-zero-install:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'yarn'
- run: yarn install --immutable
Offline Mirror / Controlled Installs
# .yarnrc.yml
enableNetwork: false # Fail if anything needs fetching
checksumBehavior: throw # Fail on checksum mismatch
Best Practices
- Use PnP as the default
nodeLinker. Only fall back tonode-modulesif a critical tool is truly incompatible. - Install editor SDKs (
yarn dlx @yarnpkg/sdks vscode) immediately after setting up a project. - Use
yarn workspaces foreach -Atfor builds to respect dependency topological order. - Use constraints to enforce consistency across workspace packages (license, version alignment, required scripts).
- Use
yarn patchinstead ofpatch-packagefor fixing broken dependencies. - Run
yarn install --immutablein CI to verify lockfile integrity. - Use
packageExtensionsin.yarnrc.ymlto fix missing peer dependency declarations in third-party packages. - Keep
.yarn/releases/committed so all team members use the exact same Yarn version. - Use
yarn dedupeto reduce duplicate dependency versions in the lockfile. - For zero-installs, commit
.yarn/cache/using Git LFS or accept the repository size trade-off.
Common Pitfalls
- PnP-incompatible packages: Some packages use dynamic
require()or hardcodenode_modulespaths. UsepackageExtensionsor fall back tonodeLinker: node-modulesas a last resort. - Missing editor SDK: TypeScript and ESLint appear broken in the editor without running
yarn dlx @yarnpkg/sdks. This is the most common source of frustration. Cannot find moduleerrors: Caused by phantom dependency access. The package must be added as an explicit dependency.- Large repository from zero-installs: Committing
.yarn/cache/bloats the Git history. Evaluate whether the trade-off is worth it for your team. - Forgetting
--immutablein CI: Without it, CI may silently modify the lockfile, masking discrepancies. - Using
npm publishinstead ofyarn npm publish: npm CLI does not understand PnP. Useyarn npm publishoryarn packfor publishing. - Postinstall scripts in PnP: Packages with native build steps need to be listed in
dependenciesMetawithbuilt: truein.yarnrc.ymlif they fail silently. - Conflating Yarn Classic (v1) and Berry (v2+): Configuration, commands, and behavior differ significantly. Yarn Berry uses
.yarnrc.yml(not.yarnrc), andyarn.lockformat changed.
Anti-Patterns
Over-engineering for hypothetical scale. Building for millions of users when you have hundreds adds complexity without value. Solve today's problems first.
Ignoring the existing ecosystem. Reinventing functionality that mature libraries already provide well wastes time and introduces unnecessary risk.
Premature abstraction. Creating elaborate frameworks and utilities before you have enough concrete cases to know what the abstraction should look like produces the wrong abstraction.
Neglecting error handling at boundaries. Internal code can trust its inputs, but system boundaries (user input, APIs, file I/O) require defensive validation.
Skipping documentation for obvious code. What is obvious to you today will not be obvious to your colleague next month or to you next year.
Install this skill directly: skilldb add package-management-skills
Related Skills
Bundling Libraries
Bundling JavaScript/TypeScript libraries for distribution using tsup, unbuild, and Rollup
Dependency Audit
Security auditing npm dependencies for vulnerabilities, license compliance, and supply chain risks
Lockfile Management
Lock file strategies for deterministic installs across npm, pnpm, and Yarn
Npm Publishing
Publishing packages to the npm registry with proper configuration, access control, and release automation
Pnpm
pnpm workspace management for monorepos with content-addressable storage and strict dependency isolation
Private Registries
Setting up and using private npm registries with Verdaccio, GitHub Packages, and GitLab Package Registry