Dependencies · Hygiene

Your React Native patch-package directory is a graveyard. Audit it.

Published May 3, 2026 · 8 minute read
TL;DR

Every long-lived React Native app has a patches/ directory. Most of the patches in it were written years ago, by people who've left, against versions of libraries that have since shipped a real fix.

You're carrying them through every upgrade. They break. You fix the broken patch instead of asking whether the patch was ever needed in the first place.

Audit annually. Or before every React Native upgrade. Expect to delete half of them.

Open your repo. Go to patches/. Count the files.

If there are zero, this post isn't for you. If there are three, you're probably fine. If there are fifteen and one of them is from 2022, keep reading.

patch-package is a fine tool. The problem isn't the tool. It's that patches accumulate, never get reviewed, and survive upgrades they shouldn't have survived. The patches directory is where engineering debt goes to be ignored.

On this page
  1. Why patches accumulate
  2. The audit, step by step
  3. Four categories of patch
  4. How to safely delete a patch
  5. Document what survives
  6. Patches you should never write
  7. FAQ

Why patches accumulate

The pattern goes like this. A library has a bug. The team is on a deadline. Someone forks the file in node_modules, fixes the bug, runs npx patch-package some-library, commits the patch, ships.

Two things were supposed to happen next. The author was supposed to open a PR upstream and link to it in the patch. Someone was supposed to come back when the fix shipped and remove the patch.

Neither happens. The PR gets opened, drags through review, eventually merges. By then nobody remembers to delete the local patch. The upstream library bumps versions; the patch reapplies (or fails and gets fixed); the cycle continues.

Multiply by three years of feature development. Twelve patches. None of them documented. Half of them obsolete.

The pattern

Patches are written under deadline pressure. Audits don't happen under deadline pressure. The structural fix is to audit on a schedule, not when a patch breaks.

The audit, step by step

One hour, end to end, for a typical app with 10–20 patches.

Step 01

Enumerate

List every file in patches/.

ls patches/

Each filename is in the form library-name+version.patch. Note the version. That's the version the patch was written against.

Step 02

Find the why

For each patch, find the commit that introduced it:

git log --diff-filter=A -- patches/library-name+1.2.3.patch

Read the commit message. Read the linked PR if there is one. If there's no context — not in the commit, not in a code comment, not in a README — that's information itself. It means nobody documented why this exists.

Step 03

Check upstream

Open the library's npm page or GitHub. Compare:

If the upstream changelog mentions a fix that matches your patch's intent, the patch is probably obsolete.

Step 04

Check usage

The patch fixes a specific code path. Is your app still calling that code path?

Search your codebase for the API the patch affects. If you stopped using the feature in 2024, the patch is dead weight. Delete it.

Four categories of patch

Every patch you find sorts into one of these.

CategorySignalWhat to do
Fixed upstreamLibrary has shipped a real fix in a version >= the one you're onDelete patch. Run install. Test.
Still neededUpstream hasn't fixed it. Your app still uses the affected code pathKeep patch. Document with a comment block. Open or link the upstream PR.
Code path deadPatch is real, but the feature it fixes is no longer used in your appDelete patch.
Library is deadThe patched library is unmaintained or has been replacedPlan to remove the library. Delete the patch when the library leaves.

Most teams find their split is roughly: 30% fixed upstream, 30% still needed, 25% code path dead, 15% library is dead. Your mileage will vary.

How to safely delete a patch

Resist the urge to bulk-delete. Each patch is a behavior change against the installed library. Removing one means the unpatched code runs.

The safe procedure:

  1. Delete the patch file from patches/.
  2. Run npm install (or yarn install). The patch no longer applies.
  3. Build the app. Run the test suite. Manually exercise the feature the patch affected.
  4. Open a PR with the deletion only. One patch per PR if you're being careful. Three or four per PR if you're not.
  5. Ship to staging or a beta channel. Let it sit a few days. If nothing surfaces, ship to production.

If the patch was a workaround for a crash, you'll find out fast. If it was a workaround for a subtle behavior bug, you might not find out for a week. That's why incremental beats bulk.

Document what survives

The patches that survive the audit need a paper trail. The next person to look at them shouldn't have to do detective work.

Create PATCHES.md at the repo root. One section per surviving patch. Each section has:

This is the kind of document that pays for itself the first time someone says "why does this patch exist?" three years from now.

Patches you should never write

Not every workaround belongs in patches/. Three patterns to push back on:

The right use of patch-package is a small, surgical, time-bounded fix while you wait for the real fix to ship. The wrong use is everything else.

About to upgrade React Native?

Audit the patches directory first. Every patch you delete now is one less thing to debug when files move under it. The free scanner will also flag patched libraries that have known CVEs in the version you're pinned to.

Frequently Asked Questions

What is patch-package and why do React Native apps use it?

patch-package is an npm tool that lets you commit changes to a node_modules dependency as a diff. On every install, the patches are reapplied. React Native apps use it because the ecosystem is full of libraries with bugs that need fixing, peer-range issues that need overriding, or native code that needs tweaking — and waiting for the upstream maintainer isn't always realistic. It works. It's also a debt magnet.

How do I audit my React Native patches?

Open the patches/ directory and list every patch file. For each one, find out three things: why the patch exists (commit message, PR, code comment), whether the upstream library has since released a fix, and whether the patched code path is still in use. Most teams find 30–60% of their patches are obsolete on the first pass. Remove the obsolete ones. Document the rest in a single PATCHES.md file.

Why do patches break during React Native upgrades?

A patch is a literal diff against a specific version of a file. When you upgrade a library, the file probably changed — different lines, different surrounding context, sometimes the function the patch touched is gone. The patch fails to apply. patch-package warns or fails, depending on configuration. You're then debugging a fix from two years ago that nobody on the team remembers writing.

Should I commit my patches to git?

Yes. The patches/ directory must be committed. patch-package reapplies the patches on install, so without them in version control, your install isn't reproducible. The mistake isn't committing the patches — it's never auditing them after they land.

What's the alternative to patch-package?

Three real alternatives. First, npm or yarn overrides — better when you need to pin a transitive version, worse when you need to change code. Second, forking and publishing under your scope — heavier setup, but the change lives in version control instead of as an opaque diff. Third, upstreaming the fix — slowest, best long-term outcome. patch-package itself is fine for short-lived emergency fixes; the failure mode is letting them become permanent.

How often should I audit React Native patches?

Every React Native upgrade, at minimum. The upgrade is the moment when half the underlying files change anyway, so it's the natural inflection point to ask whether each patch is still needed. Some teams add it to a quarterly hygiene checklist. The wrong answer is "whenever a patch breaks" — by that point, you're auditing under pressure.