| |

Yarn 12 ๐Ÿงถ Patching Dependencies and yarn patch

โฑ๏ธ Estimated read: 9 min | |

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

CommandPurpose
yarn patch <package>Extract package to a temp folder
yarn patch <package> --updateExtract 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

PathPurpose
.yarn/patches/Patch files (default patchFolder)
package.json โ†’ resolutionspatch: protocol entries
/tmp/yarn--*Temporary extraction directory

Patch Limitations

LimitationWorkaround
Cannot add dependenciesUse packageExtensions
Cannot modify binary filesAvoid; patches are text-based
Version-specificRecreate or update on upgrade
Minified files problematicEdit 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

PitfallWhy It HappensFix
Patch not applied after installpatch-commit run without -sRe-run with -s to save and register
Patch lost after upgradePatch is version-specificRecreate with yarn patch on new version
Existing changes overwrittenyarn patch resets by defaultUse --update to include existing patch
Cannot add dependency via patchPatches computed at fetch timeUse packageExtensions
Patch file missing from Git.yarn/patches not committedgit 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

ItemValue
Extract commandyarn patch <package>
Update flag--update (or -u)
Commit commandyarn patch-commit -s <folder>
Patch storage.yarn/patches/
Registrationresolutions in package.json
Protocolpatch:
Version-specificYes
Dependency additionsNot possible via patch

Key takeaways:

  • yarn patch extracts, yarn patch-commit -s saves. The -s flag 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 .
  • --update preserves existing patches. Without it, yarn patch resets to the original package, discarding previous changes .
  • Patches cannot add dependencies. The patch is computed at fetch time, after resolution. Use packageExtensions for dependency changes .
  • Commit the patch file. The .yarn/patches/ directory must be versioned alongside package.json and yarn.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.

Was this helpful?


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!