netresearch/composer-patches-plugin
Composer plugin that automatically applies patches to your dependencies after install and update. Define local or remote diff files in composer.json to keep third-party packages fixed without forking. Helps make dependency patching reproducible and easy to manage across environments.
Install the plugin as a project dependency (not a global install):
composer require --dev netresearch/composer-patches-plugin
If your production build runs composer install --no-dev, install it in require instead so patches are applied in production builds too.
Allow the plugin on Composer 2.2+:
{
"config": {
"allow-plugins": {
"netresearch/composer-patches-plugin": true
}
}
}
Without this, interactive installs prompt and CI installs fail.
Add patch definitions under extra in composer.json. The package follows the common Composer patch convention of mapping package names to patch locations (confirm the exact key and schema in the package README; it is typically extra.patches):
{
"extra": {
"patches": {
"vendor/package": {
"Fix null handling in importer": "patches/vendor/package/fix-null-importer.patch"
}
}
}
}
Run a clean install and watch the plugin output:
rm -rf vendor/vendor/package
composer install -v
A successful run reports that the patch was applied. A failed run aborts the install and shows the patch command output.
Where to look first
extra key, supported patch value formats (local path, URL, nested arrays), and any CLI commands.composer.json / src/ of the plugin for the config schema and the Composer event(s) it subscribes to (typically post-install-cmd / post-update-cmd or package install events).composer.lock before and after an upgrade when a patch starts failing.First real use case: patch a one-line bug in a vendor package that has no upstream release yet. Put a git diff-style patch in patches/, reference it from extra.patches, commit both, and verify with a clean composer install in CI.
patches/<vendor>/<package>/<short-description>.patch. This makes them reviewable and ensures every developer and CI run uses the same patch content.a/ and b/ prefixes:
git diff --no-index --src-prefix=a/ --dst-prefix=b/ original/ modified/ > fix.patch
Patches are normally applied with -p1, so paths should look like a/src/Foo.php and b/src/Foo.php.fix-null-importer.patch, not vendor-package-1.2.3.patch. The patch is tied to code, not to the installed version string.composer update vendor/package --with-dependencies, then immediately do a clean install to see whether the patch still applies. If it fails, regenerate it against the new version rather than adding fuzz.composer install from a clean checkout is the only reliable way to prove patches apply. Developers with an existing vendor/ directory may never exercise the plugin.vendor/) and reinstall. Changing a patch file alone usually does not cause the plugin to reapply it.patches/README.md entry with the upstream issue/PR link, the reason for the patch, and a removal condition (“remove when >= 2.4.1 is released”). This prevents patches from becoming permanent folklore.vendor/ or ship a build artifact, the plugin only needs to run in the build environment. Keep the patch files in the repository regardless so future builds are reproducible.require/allow-plugins, and run a clean install to compare results.allow-plugins is the most common first failure. On Composer 2.2+, CI will refuse to run the plugin unless it is explicitly allowed. Commit the config.allow-plugins entry.composer.lock. Two environments can have identical lockfiles but different vendor/ contents if one did not run the plugin. Enforce clean installs in CI and avoid committing a vendor/ directory that was built without patches.patch can apply a hunk with offset or fuzz against a slightly different version. Inspect output with -v and prefer regenerating the patch against the exact installed version..gitattributes and generate patches in the same environment as CI where possible.patch does not apply Git binary patches; verify whether this plugin uses git apply --binary or supports binary patches before relying on them.patch binary or behave differently with path separators. Confirm the plugin’s patch backend and test on the same OS family as your developers/CI.--no-dev can silently skip the plugin. If the plugin is in require-dev and production builds use --no-dev, patches will not be applied in production. Put it in require if production builds install from source.composer install -vvv, capture the exact patch command and working directory, and reproduce it manually from the package root. Most failures are path-prefix (-p1 vs -p0), wrong package version, or a stale patch.How can I help you explore Laravel packages today?