Yarn 09 ๐งถ Zero-Installs Configuration
Zero-Installs is a Yarn pattern that eliminates the need to run yarn install after cloning a repository or switching branches. It works by committing the install artifactsโthe PnP loader files and the project-local package cacheโdirectly to version control. The result is a repository that is immediately runnable on checkout, with no network requests and no installation step. Yarn 4 disabled Zero-Installs by default for new projects, but the pattern remains fully supported and documented for teams that choose it .
Key point: Zero-Installs requires three things committed to Git: enableGlobalCache: false in .yarnrc.yml, the .yarn/cache/ directory containing package archives, and the .pnp.cjs loader file. Without all three, the repository is not self-contained.
Why Zero-Installs exists
The branch-switching problem. In a traditional node_modules setup, switching branches often changes the lockfile. The developer must remember to run yarn install before running tests or starting the dev server. If they forget, tools crash with confusing errors. Zero-Installs makes git checkout effectively double as yarn install: the VCS updates the cache and loader files as part of the branch switch, and the project is immediately runnable .
The network reliability problem. Every yarn install fetches packages from the npm registry. When the registry has an outageโor when a package is unpublishedโthe install fails. By committing the cache to the repository, every commit is guaranteed to be installable regardless of external service availability. The repository becomes its own package registry .
The node_modules problem. Checking in node_modules is technically possible but impractical. The directory contains tens of thousands of files, hoisting causes them to move unpredictably when dependencies change, and developers have a bad habit of editing files inside it manually. Git tracks every change as a separate diff, bloating the repository and making reviews impossible . Zero-Installs with PnP avoids this: the cache contains one zip archive per package, the dependency tree is flat, and Git can track each package as a single file .
The Yarn 4 default change. Yarn 4 no longer enables Zero-Installs by default for new projects created with yarn init . This is not because the pattern is deprecatedโit remains fully supportedโbut because Yarn 4 introduced Lazy Installs as an alternative that scales better on very large monorepos. Zero-Installs remains a viable choice for smaller projects or teams that prioritize reproducibility over repository size .
The trade-off. Committing the cache increases repository size. The .yarn/cache directory contains one zip per dependency, and for large projects, this can add hundreds of megabytes to the repository. The .pnp.cjs file also grows with the dependency graph, and in very large monorepos, it can reach tens of megabytes on its own . The benefit is complete reproducibility and zero install time.
a. Enabling the local cache and committing artifacts
The first step is configuring Yarn to store packages in the project directory rather than the global cache. By default, Yarn Berry uses a global cache in ~/.yarn/berry/cache, which is not portable across machines. Setting enableGlobalCache: false in .yarnrc.yml redirects the cache to .yarn/cache within the project .
# .yarnrc.yml
enableGlobalCache: false
nodeLinker: pnp
After changing this setting, run yarn install to populate the local cache. The .yarn/cache/ directory will contain one .zip file for each package in the dependency tree. The .pnp.cjs file is also generated at the project root.
The .gitignore file must be updated to not ignore these artifacts. A typical Yarn .gitignore ignores .yarn/* and .pnp.*, which would exclude the exact files Zero-Installs requires . The correct configuration explicitly un-ignores the cache and loader files.
# .gitignore
.yarn/*
!.yarn/cache
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.pnp.*
!.pnp.cjs
!.pnp.loader.mjs
The negation patterns (!) tell Git to include these paths even though the parent directory is ignored. After adding the cache and loaders, commit them alongside .yarnrc.yml and yarn.lock.
b. Verifying Zero-Installs in CI
A repository with Zero-Installs should be validated to ensure the committed artifacts are consistent with the lockfile and that no package has been tampered with. Yarn provides two flags for this: --immutable-cache and --check-cache .
# Validate that the cache matches the lockfile
yarn install --immutable --immutable-cache
# Also verify checksums of cached packages (recommended for external PRs)
yarn install --immutable --immutable-cache --check-cache
The --immutable flag prevents Yarn from modifying the lockfile. The --immutable-cache flag aborts if the cache would need to be modifiedโeither because a package is missing or because the lockfile references a package not present in the cache . The --check-cache flag is the security layer: it refetches packages and verifies that their checksums match what the lockfile and the committed cache contain. This is essential when accepting pull requests from third parties, as a malicious contributor could otherwise alter the committed cache files before submitting the PR .
For a CI workflow, the install step with these flags is the only verification needed. If the cache is missing a package or the checksums do not match, the build fails immediately rather than proceeding with an inconsistent state.
c. Limitations and when to avoid Zero-Installs
Zero-Installs has specific limitations that determine whether it is appropriate for a project. The most significant is native dependencies. Packages that compile native code (using node-gyp, for example) cannot be executed directly from within a zip archive. When such a package is added or updated, yarn install must be run to build the native component . Yarn displays a helpful error message if this is forgotten, but the pattern is not entirely install-free for these packages.
The second limitation is repository size. The .pnp.cjs file contains the full dependency map and can grow large in monorepos with many workspaces. In one documented case, the .pnp.cjs file alone reached 25 MiB, and Git’s delta algorithm handled it poorly . The cache itself also adds size, though the zips are uncompressed to allow Git to compute deltas between versionsโcounterintuitively, uncompressed zips produce a smaller repository over time than compressed ones .
The third limitation is the Yarn version upgrade path. Some Yarn releases have required regenerating the entire cache, producing a large diff in Git. Modern Yarn versions control the byte representation of cache files more carefully, reducing unnecessary updates, but the risk remains .
For very large monorepos with frequent dependency changes, Yarn’s Lazy Installs is the recommended alternative. It does not commit the cache, but uses a local cache and a smarter install strategy to reduce the cost of switching branches. Zero-Installs remains appropriate for smaller projects, internal tools, or teams that prioritize absolute reproducibility over repository size .
Complete Example Session
# ============================================
# PART 1: CONFIGURE LOCAL CACHE
# ============================================
# .yarnrc.yml
enableGlobalCache: false
nodeLinker: pnp
# ============================================
# PART 2: RUN INSTALL TO POPULATE CACHE
# ============================================
yarn install
# The local cache is populated at .yarn/cache/
# The loader is generated at .pnp.cjs
# ============================================
# PART 3: UPDATE GITIGNORE
# ============================================
# .gitignore
.yarn/*
!.yarn/cache
!.yarn/releases
.pnp.*
!.pnp.cjs
!.pnp.loader.mjs
# ============================================
# PART 4: VERIFY THE CACHE EXISTS
# ============================================
ls .yarn/cache/ | head -n 5
# Output: package-name-npm-1.0.0-abc123.zip
# ============================================
# PART 5: COMMIT THE ARTIFACTS
# ============================================
git add .yarnrc.yml .yarn/cache .pnp.cjs .pnp.loader.mjs yarn.lock
git commit -m "Enable Zero-Installs"
git push
# ============================================
# PART 6: VERIFY ON A FRESH CLONE
# ============================================
git clone <repository-url> test-clone
cd test-clone
ls node_modules 2>/dev/null || echo "No node_modules (expected)"
# The project is immediately runnable
yarn node -e "console.log('Zero-Installs works')"
# ============================================
# PART 7: CI VALIDATION
# ============================================
# In CI, validate the committed cache
yarn install --immutable --immutable-cache --check-cache
The seven parts trace the Zero-Installs setup: configuring the local cache, running install, updating .gitignore, verifying the cache, committing the artifacts, testing on a fresh clone, and validating in CI.
Quick Reference
Required Configuration
| Setting | Location | Value |
|---|---|---|
enableGlobalCache | .yarnrc.yml | false |
nodeLinker | .yarnrc.yml | pnp |
| Cache directory | .yarn/cache/ | Committed to Git |
| Loader file | .pnp.cjs | Committed to Git |
CI Validation Flags
| Flag | Purpose |
|---|---|
--immutable | Lockfile must not change |
--immutable-cache | Cache must not change |
--check-cache | Verify package checksums |
Files to Commit
| File/Directory | Purpose |
|---|---|
.yarnrc.yml | Configuration |
yarn.lock | Dependency resolutions |
.yarn/cache/ | Package archives |
.pnp.cjs | PnP loader |
.pnp.loader.mjs | ESM loader |
Best Practices
โ Do This:
enableGlobalCache: false
<!-- Local cache is required for Zero-Installs --> # โ
yarn install --immutable --immutable-cache --check-cache
<!-- Validate cache in CI --> # โ
!.yarn/cache
!.pnp.cjs
<!-- Un-ignore Zero-Installs artifacts --> # โ
โ Don’t Do This:
# Commit node_modules instead of .yarn/cache
<!-- Bloats repo, breaks on hoisting changes --> # โ
# Ignore .yarn/cache in .gitignore
<!-- Zero-Installs requires the cache --> # โ
# Skip --check-cache with external PRs
<!-- Allows cache tampering --> # โ
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Fresh clone fails to run | .yarn/cache not committed | Un-ignore with !.yarn/cache |
| Cache mismatch in CI | Local cache differs from lockfile | Run yarn install and commit updated cache |
| Native dependency fails | Zip cannot contain compiled binaries | Run yarn install after adding native deps |
| Repository too large | Cache and .pnp.cjs committed | Consider Lazy Installs for large monorepos |
| Tampered cache in PR | Contributor modified zip files | Use --check-cache in CI |
Real-World Examples
1. Enable Local Cache
enableGlobalCache: false
2. Commit Cache
git add .yarn/cache .pnp.cjs yarn.lock
3. Un-Ignore Cache
!.yarn/cache
!.pnp.cjs
4. Fresh Clone Test
git clone <url> && cd <repo> && yarn node -e "console.log('ok')"
5. CI Validation
yarn install --immutable --immutable-cache --check-cache
6. Check Cache Size
du -sh .yarn/cache
7. List Cached Packages
ls .yarn/cache | wc -l
8. Native Dependency Note
Adding a native package requires yarn install to compile.
9. Fallback to Global Cache
enableGlobalCache: true
10. Switch to Lazy Installs
Remove cache from Git; Yarn 4 defaults to Lazy Installs.
Visual
Zero-Installs Repository Contents
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Repository (after Zero-Installs commit) โ
โ โ
โ โโโ .yarnrc.yml โ
โ โ โโโ enableGlobalCache: false โ
โ โโโ yarn.lock โ
โ โโโ .pnp.cjs (dependency map) โ
โ โโโ .pnp.loader.mjs (ESM loader) โ
โ โโโ .yarn/ โ
โ โโโ cache/ โ
โ โโโ lodash-npm-4.17.21-abc.zip โ
โ โโโ express-npm-4.18.2-def.zip โ
โ โโโ ... โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The repository contains everything needed to run without yarn install.
CI Validation Flow
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CI runner checks out repository โ
โ (cache and loaders are present) โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ yarn install --immutable --immutable-cache โ
โ --check-cache โ
โ โ
โ โโ Lockfile matches cache? โ
โ โโ Checksums match? โ
โ โโ No modifications required? โ
โโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโ
โ PASS โ FAIL
โผ โผ
โโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโ
โ Proceed with tests โ โ Abort: cache is โ
โ โ โ inconsistent โ
โโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโ
The CI validation ensures the committed cache has not been tampered with and matches the lockfile.
Summary
| Item | Value |
|---|---|
| Zero-Installs definition | Commit cache and loaders to Git |
| Required setting | enableGlobalCache: false |
| Cache location | .yarn/cache/ |
| Loader files | .pnp.cjs, .pnp.loader.mjs |
| CI validation | --immutable --immutable-cache --check-cache |
| Native dependency caveat | Requires yarn install when added |
| Yarn 4 default | Disabled for new projects |
| Alternative | Lazy Installs |
Key takeaways:
- Zero-Installs makes
git checkoutequivalent toyarn install. The cache and loader files are committed, so the repository is immediately runnable on clone or branch switch . enableGlobalCache: falseis mandatory. Without it, Yarn references the machine-global cache, which is not portable across systems .- The
.gitignoremust un-ignore the cache. The default Yarn.gitignoreexcludes.yarn/*and.pnp.*, which would defeat Zero-Installs . - CI must validate the cache. The
--check-cacheflag verifies that committed packages have not been tampered with, which is critical when accepting external contributions . - Native dependencies require
yarn install. Packages with compiled binaries cannot run from zip archives; Yarn displays an error if the install is forgotten . - Yarn 4 does not enable it by default. New projects use Lazy Installs instead. Zero-Installs is an opt-in pattern for teams that need absolute reproducibility .
Remember: Zero-Installs is a reproducibility pattern, not a performance optimization. It eliminates the install step by committing the dependency artifacts to the repository. The trade-off is repository size. For small projects and internal tools, the trade-off is worth it. For large monorepos, Lazy Installs is the recommended alternative.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!