Self‑Documenting Composer Patch Management with composer‑darn
If you have maintained a Drupal site of any size for more than a year, you have likely seen how quickly a composer.json file can fill with patch entries that have little or no context. A URL, maybe a one-line description if you're lucky, and no record of why the patch exists, whether it's still needed, or what happens if you remove it. By the time the next upgrade cycle comes around, every patch can feel like a small investigation.
The tool most PHP teams already use to apply patches, cweagans/composer-patches, does that job well. It applies patches declared in composer.json during install and update, and it's especially common in Drupal projects. What it doesn't do is help you manage those declarations. It makes no assumptions about labeling, organization, or sourcing, which means the documentation quality of your patch list is entirely dependent on how disciplined your team was when each patch was added.
We made composer-darn to fix that by supplementing composer-patches with metadata from the same places teams already find patches, including issue queues and pull requests.
Managing Composer Patches with Better Context
composer-darn turns patch registration into a more structured workflow. It fetches, registers, and organizes patches from the sources teams already use, including Drupal.org issues, GitHub pull requests, direct .patch or .diff URLs, and local files. Point it at a source, and it handles the rest.
composer darn https://www.drupal.org/project/drupal/issues/3151000
composer darn https://github.com/owner/repo/pull/123For a Drupal.org issue, it queries the Drupal.org API, resolves the package name, lists every available patch on the issue, including merge requests and file attachments, with the newest options shown first, and lets you pick one. That path is Drupal-specific, since Drupal.org is where those issues and patch discussions live.
For a GitHub PR, it auto-detects the package from the repo's composer.json and pulls the PR title as the default description. This path works for any Composer project, regardless of ecosystem.
Either way, the patch file lands in a predictable patches/<package>/ directory, and the composer.json entry it writes is self-documenting by construction, with the source, issue or PR reference, and a real description included every time.
Keeping Patch Records Accurate Over Time
Once patches are registered, the next challenge is keeping the patch list accurate as the project changes. Two commands are especially useful for that work.
composer darn:verify checks that every patch referenced in composer.json exists on disk, flags duplicates, and catches a patches directory that has accidentally been added to .gitignore. It exits with code 1 when it finds a problem, which makes it a natural fit for CI checks.
composer darn:fix is designed for teams adopting composer-darn into a project that already has a pile of undocumented patch entries. It re-fetches metadata for every remote patch and rewrites the entries into the standard, self-documenting format. That gives existing projects a practical path into the same structure, without requiring teams to start from a clean slate.
Additional commands help with routine cleanup and visibility. composer darn:prune removes orphaned patch files and stale entries, while composer darn:list shows which registered patches are actually present on disk.
Getting Started with composer-darn
composer require --dev bounteous-inc/composer-darn
composer require cweagans/composer-patchescomposer-darn will offer to install cweagans/composer-patches for you if it's missing. If you're adding it to a project that already has patches declared, it will detect them and offer to run composer darn:fix automatically.
Why We Are Open-Sourcing composer-darn
composer-darn started the way many useful internal tools do, with a real Drupal project and a patch that took longer than it should have to untangle because no one could quickly answer why it was there.
We built the fix for ourselves first, and after using it on another project, it became clear that the problem was not unique to one team or one codebase. Any team carrying patched Composer dependencies, Drupal or otherwise, has hit some version of the same wall.
At Bounteous, durable engineering practices often begin with recognizing when a recurring project challenge is really a broader maintainability problem worth solving beyond a single codebase, then turning that insight into systems and tools that make future work clearer, faster, and easier to sustain. Once we saw the same patch-management problem across projects, open-sourcing composer-darn felt like the natural next step. It's a small tool built around a shared problem, and making it available gives other teams a way to use it, test it in their own workflows, and improve it over time.
Try composer-darn in Your Project
The quickest way to see the difference is to point composer-darn at one patch you already have registered and run composer darn:fix. It will re-document that entry in the standard format and make the source context easier to review.
From there, try registering your next patch straight from a Drupal.org issue or GitHub PR and let it write the description for you. If something doesn't fit your workflow, open an issue. If you've got a fix, pull requests are welcome, and the contribution guide is available in the repo.
composer-darn is MIT licensed and requires PHP 8.2+ and Composer 2.0+. You can find the project on GitHub and Packagist.
GitHub
github.com/Bounteous-Inc/composer-darn
Packagist
packagist.org/packages/bounteous-inc/composer-darn
News & Insights
Featured Perspectives