Yarn 12 ๐งถ Patching Dependencies and yarn patch
A dependency has a bug. The upstream fix is months away, or the maintainer is unresponsive, or the fix exists only in a pull request that has not been merged. Forking the repository is heavy: you lose the link to the original, you must maintain the fork, and your package.json points to a Git URL that may break. Yarn’s built-in patch mechanism solves this without forking: it extracts the package into a temporary directory, lets you edit the files directly, and generates a patch file that Yarn applies automatically on every install. The patch is committed to the repository, versioned alongside the code, and applied consistently across every machine and CI runner.
Key point: yarn patch <package> extracts the package for editing. yarn patch-commit -s <folder> generates the patch file and registers it in package.json via the patch: protocol. The patch is version-specific: if the dependency version changes, the patch must be recreated or updated.
Why yarn patch exists
The upstream lag problem. A critical bug blocks your application. The fix is a one-line change, but the package maintainer has not released a new version. The Yarn documentation recommends making a pull request upstream, but acknowledges that review and release can take time . In the meantime, yarn patch lets you unblock yourself without waiting.
The forking overhead problem. The alternative to patching is forking the repository and pointing package.json at your fork. This works, but it introduces a maintenance burden: you must keep the fork synchronized with upstream, and the git: protocol reference is fragile. The patch: protocol keeps the original package intact and applies only the diff you specify .
The node_modules editing problem. Developers often edit files directly in node_modules while debugging. Those edits disappear on the next yarn install. The patch workflow captures those edits as a persistent diff that survives reinstalls. However, the standard Yarn workflow requires you to edit the extracted folder, not node_modules. Tools like yarn-easy-patch exist to bridge this gap by copying changes from node_modules into the patch folder automatically .
The patch lifecycle problem. Patches are computed at fetch time, not resolution time. This means the patched package’s dependencies are already resolved before the patch is applied. The practical consequence is that yarn patch cannot add new dependencies to a package; for that, packageExtensions is the correct mechanism .
The trade-off. A patch is a divergence from the published package. It must be documented, reviewed, and removed when the upstream fix lands. An undocumented patch is technical debt that the next developer will discover only when the package is upgraded and the patch silently fails to apply.
a. Creating a patch with yarn patch
The workflow begins with yarn patch <package-name>. Yarn extracts the specified package into a temporary directory and prints the path.
# Extract the package for editing
yarn patch lodash
# Output: A temporary folder path, e.g. /tmp/yarn--1234567890-0/lodash
The extracted folder contains the exact files that Yarn would have installed. You can edit any file in that directory: JavaScript source, TypeScript declarations, configuration files, or README. The changes are isolated to the temporary copy and do not affect the installed package until the patch is committed.
If the package already has a patch applied, yarn patch resets to the original version by default. To include the existing patch in the extracted copyโso you can build on top of itโuse the --update (or -u) flag .
# Extract with the existing patch applied
yarn patch lodash --update
b. Committing the patch with patch-commit
After editing the extracted files, yarn patch-commit -s <folder> generates the patch. The -s (or --save) flag is critical: without it, the patch is printed to stdout but not saved. With it, Yarn writes the patch file to .yarn/patches/ and adds a resolutions entry to the top-level package.json that references the patch via the patch: protocol .
# Generate and save the patch
yarn patch-commit -s /tmp/yarn--1234567890-0/lodash
The resulting package.json contains a resolutions field:
{
"resolutions": {
"lodash@^4.17.21": "patch:lodash@npm%3A4.17.21#./.yarn/patches/lodash-npm-4.17.21-abc123.patch"
}
}
The patch file in .yarn/patches/ is a standard unified diff. It is committed to Git alongside the lockfile and the cache (if Zero-Installs is enabled). On every subsequent yarn install, Yarn applies the patch automatically .
The -s flag is not optional in practice. Without it, the patch exists only on stdout and is not registered. The next install will not apply it.
c. Updating and maintaining patches
Patches are version-specific. The patch file is named with the package version (e.g., lodash-npm-4.17.21-abc123.patch). When the dependency is upgraded to a new version, the old patch does not apply automatically. The workflow for updating depends on whether the files you patched changed in the new version.
If the patched files are unchanged in the new version, the patch filename and the resolutions entry can be updated manually to reference the new version. If the files changed, yarn patch must be run again against the new version, the changes must be reapplied, and a new patch must be committed .
To modify an existing patch without losing its changes, use --update to extract the patched version, make additional edits, and run yarn patch-commit -s again. The patch is regenerated, replacing the previous one .
# Update an existing patch
yarn patch lodash --update
# Edit the extracted folder
yarn patch-commit -s /tmp/yarn--new-path/lodash
The --update flag is the only safe way to build on an existing patch. Without it, the default behavior resets the patch to the original package, discarding all previous changes.
Complete Example Session
# ============================================
# PART 1: IDENTIFY THE BUG
# ============================================
# The "tiny-invariant" package throws an error
# with an unhelpful message on empty strings.
# The fix is a one-line change to the error message.
# ============================================
# PART 2: EXTRACT THE PACKAGE
# ============================================
yarn patch tiny-invariant
# Output: A temporary folder path.
# Example: /tmp/yarn--1700000000-0/tiny-invariant
# ============================================
# PART 3: EDIT THE FILES
# ============================================
# Open the extracted folder in an editor.
# Modify src/index.ts or dist/index.js.
# The change: add context to the error message.
# ============================================
# PART 4: COMMIT THE PATCH
# ============================================
yarn patch-commit -s /tmp/yarn--1700000000-0/tiny-invariant
# Patch saved to .yarn/patches/tiny-invariant-npm-1.3.3-xyz.patch
# package.json updated with resolutions entry.
# ============================================
# PART 5: VERIFY THE PATCH IS APPLIED
# ============================================
yarn install
# Yarn applies the patch during install.
# Check the installed file to confirm the change.
# ============================================
# PART 6: COMMIT TO GIT
# ============================================
git add .yarn/patches/tiny-invariant-npm-1.3.3-xyz.patch
git add package.json
git commit -m "Patch tiny-invariant error message"
# ============================================
# PART 7: UPDATE THE PATCH LATER
# ============================================
yarn patch tiny-invariant --update
# Edit the extracted folder again.
yarn patch-commit -s /tmp/yarn--new-path/tiny-invariant
# The patch is regenerated.
# ============================================
# PART 8: REMOVE THE PATCH
# ============================================
# When the upstream fix is released:
# 1. Upgrade the dependency to the fixed version.
yarn up tiny-invariant@latest
# 2. Remove the resolutions entry from package.json.
# 3. Delete the patch file from .yarn/patches/.
# 4. Run yarn install.
The eight parts trace the patch lifecycle: identifying the need, extracting, editing, committing, verifying, versioning, updating, and removing. The critical step is patch-commit -sโwithout it, the patch is not saved and not registered.
Quick Reference
Patch Commands
| Command | Purpose |
|---|---|
yarn patch <package> | Extract package to a temp folder |
yarn patch <package> --update | Extract with existing patch applied |
yarn patch-commit -s <folder> | Save patch to .yarn/patches/ and register in package.json |
yarn patch-commit <folder> | Print patch to stdout (not saved) |
File Locations
| Path | Purpose |
|---|---|
.yarn/patches/ | Patch files (default patchFolder) |
package.json โ resolutions | patch: protocol entries |
/tmp/yarn--* | Temporary extraction directory |
Patch Limitations
| Limitation | Workaround |
|---|---|
| Cannot add dependencies | Use packageExtensions |
| Cannot modify binary files | Avoid; patches are text-based |
| Version-specific | Recreate or update on upgrade |
| Minified files problematic | Edit source, not minified output |
Best Practices
โ Do This:
yarn patch-commit -s /tmp/yarn--path/package
# Always use -s to save and register the patch
yarn patch <package> --update
# Use --update to build on existing patches
# Document the reason for the patch in the commit message
โ Don’t Do This:
yarn patch-commit /tmp/yarn--path/package
# Without -s: patch printed but not saved
# Edit node_modules directly and expect it to persist
# Changes are lost on next install
# Leave the patch undocumented
# The next developer will not know why it exists
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Patch not applied after install | patch-commit run without -s | Re-run with -s to save and register |
| Patch lost after upgrade | Patch is version-specific | Recreate with yarn patch on new version |
| Existing changes overwritten | yarn patch resets by default | Use --update to include existing patch |
| Cannot add dependency via patch | Patches computed at fetch time | Use packageExtensions |
| Patch file missing from Git | .yarn/patches not committed | git add .yarn/patches/ |
Real-World Examples
1. Extract for Patching
yarn patch lodash
2. Save the Patch
yarn patch-commit -s /tmp/yarn--path/lodash
3. Update an Existing Patch
yarn patch lodash --update
4. View the Patch File
cat .yarn/patches/lodash-npm-4.17.21-abc.patch
5. Verify the Resolution
grep "patch:" package.json
6. Commit Patch to Git
git add .yarn/patches package.json
7. Remove a Patch
# Delete the file and the resolutions entry
rm .yarn/patches/lodash-npm-4.17.21-abc.patch
8. Check Patch Folder
ls .yarn/patches/
9. Apply Patch on CI
yarn install --immutable
# Patches are applied automatically from .yarn/patches
10. View Patch Diff
git diff .yarn/patches/
Visual
Patch Workflow
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ yarn patch lodash โ
โ โ Extract to /tmp/yarn--path/lodash โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Edit files in the extracted folder โ
โ (source, dist, types, etc.) โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ yarn patch-commit -s /tmp/yarn--path/lodash โ
โ โ Patch saved to .yarn/patches/ โ
โ โ package.json resolutions updated โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ git add .yarn/patches package.json โ
โ โ Patch applied on every yarn install โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The -s flag is the commit point. Without it, the patch is not saved.
Patch vs Fork
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ PATCH โ
โ โโโ Original package unchanged โ
โ โโโ Small diff in .yarn/patches/ โ
โ โโโ Easy to review and remove โ
โ โโโ Version-specific โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ FORK โ
โ โโโ Full copy of repository โ
โ โโโ Must maintain synchronization โ
โ โโโ package.json points to fork URL โ
โ โโโ Heavy, fragile โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Patches are for small, temporary fixes. Forks are for long-term divergence.
Summary
| Item | Value |
|---|---|
| Extract command | yarn patch <package> |
| Update flag | --update (or -u) |
| Commit command | yarn patch-commit -s <folder> |
| Patch storage | .yarn/patches/ |
| Registration | resolutions in package.json |
| Protocol | patch: |
| Version-specific | Yes |
| Dependency additions | Not possible via patch |
Key takeaways:
yarn patchextracts,yarn patch-commit -ssaves. The-sflag is mandatory for the patch to be registered and applied on subsequent installs .- Patches are version-specific. When the dependency is upgraded, the patch must be recreated or manually updated .
--updatepreserves existing patches. Without it,yarn patchresets to the original package, discarding previous changes .- Patches cannot add dependencies. The patch is computed at fetch time, after resolution. Use
packageExtensionsfor dependency changes . - Commit the patch file. The
.yarn/patches/directory must be versioned alongsidepackage.jsonandyarn.lock.
Remember: A patch is a temporary divergence. It should be minimal, documented, and removed when the upstream fix lands. The workflow is three commands: extract, edit, commit. The -s flag is the difference between a patch that works and one that exists only in a terminal’s scrollback buffer.
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!