npm-force-resolutions is a small tool that rewrites your package-lock.json to force a specific version of a transitive dependency, giving older npm the selective-resolution capability Yarn shipped years earlier. It exists to solve a real and common problem: a deeply nested dependency has a known vulnerability, the parent package has not published a fix, and you need to override the version yourself.
If you are on a modern npm, you probably do not need this package at all anymore, and understanding why is the point of this review. Teams also search for it as "npm force resolutions" or just "npm resolutions."
The problem it was built for
Say your app depends on some-lib, which depends on vulnerable-pkg@1.2.0, and that nested version has a published advisory. You cannot fix it directly because you never named vulnerable-pkg in your package.json; it arrived transitively. The maintainer of some-lib has not bumped it. You are stuck shipping the flaw.
npm-force-resolutions lets you declare the version you want and rewrites the lockfile to honor it:
{
"resolutions": {
"vulnerable-pkg": "1.2.5"
},
"scripts": {
"preinstall": "npx npm-force-resolutions"
}
}
The preinstall hook runs the tool before npm install, editing package-lock.json so the resolved graph uses the patched version wherever it appears.
Why the preinstall-hook design carries risk
The mechanism is clever but it has sharp edges worth naming in a security review:
- It runs an install-time script.
preinstallexecutes automatically onnpm install, and fetching a tool vianpxat install time means you are running whatever version resolves at that moment unless you pin it. Install-time script execution is precisely the vector many supply-chain attacks use. - It mutates the lockfile. The tool edits
package-lock.jsonin place. If the edit and the install race, or if the lockfile shape changed across npm versions, results can be inconsistent. - npm 7 and later changed the lockfile format. Users reported that resolutions did not apply reliably for all dependencies once npm moved to the v2 and v3 lockfile format, because the tool was designed against the older layout.
None of this makes the tool malware; it is a legitimate, widely used package. But relying on an install-time script that rewrites your lockfile is more fragile and more attack-adjacent than the native alternative that now exists.
The native replacement: npm overrides
Since npm 8.3.0 (which ships with Node 16 and later), npm has a built-in overrides field that does the same job without any script, any npx fetch, or any lockfile surgery:
{
"overrides": {
"vulnerable-pkg": "1.2.5"
}
}
You can also scope an override to a specific parent so you only change the version under one dependency:
{
"overrides": {
"some-lib": {
"vulnerable-pkg": "1.2.5"
}
}
}
This is declarative, runs as part of normal dependency resolution, and requires no preinstall hook. For anyone on a current npm, overrides is the right answer and npm-force-resolutions is effectively superseded. Yarn's equivalent is the resolutions field, and pnpm uses pnpm.overrides.
When the old tool is still justified
There is a narrow legitimate case: a legacy project locked to npm 6.x on Node 12.x, where the native overrides field does not exist. There, npm-force-resolutions remains a workable bridge. Even then, harden it: pin the tool to an exact version rather than floating through npx, and treat the pinned version as a dependency you scan and update deliberately.
The bigger point: overrides are a patch, not a cure
Whether you use native overrides or the older tool, forcing a transitive version is a stopgap. You are pinning a version the parent package was not tested against, which can cause subtle breakage. The durable fix is upstream: the parent maintainer bumps the dependency, or you migrate off an unmaintained parent.
Overrides also do not track future advisories on their own. Once you pin vulnerable-pkg@1.2.5, you need something watching for the next CVE against that line. This is where continuous software composition analysis matters: an SCA tool such as Safeguard can flag when a version you have force-pinned itself becomes vulnerable, so a manual override does not quietly rot into a new exposure. Our security academy covers a full transitive-remediation workflow.
FAQ
Is npm-force-resolutions safe to use?
It is a legitimate package, but its design runs an install-time preinstall script and rewrites your lockfile, which is fragile and attack-adjacent. On npm 8.3.0 and later, prefer the native overrides field, which achieves the same result without any script.
What replaced npm-force-resolutions?
The native overrides field in package.json, available since npm 8.3.0 (bundled with Node 16 and later). It pins transitive dependency versions declaratively as part of normal resolution, with no preinstall hook or lockfile surgery.
Why did npm-force-resolutions stop working reliably on newer npm?
npm 7 changed the package-lock.json format to v2, and later v3. The tool was built against the older lockfile layout, so users reported resolutions not applying to all dependencies on newer npm versions.
Do version overrides fix vulnerabilities permanently?
No. Forcing a transitive version is a stopgap that pins a version the parent was not tested against. The durable fix is upstream, and you still need dependency monitoring to catch future advisories against the version you pinned.