Debuggin NPM
Overriding dependencies
Overrides are most valuable when you know exactly which packages in your tree are EOL or carrying unpatched CVEs — but finding them manually across hundreds of dependencies isn't practical.
When you're deep in a project and a sub-dependency has a security vulnerability and breaks your build or triggers a security alert, you need surgical precision to fix it. In other words, you override it!
Overrides (NPM 8+)
The overrides field in package.json is the native way to force NPM to use a specific version of a dependency project-wide.
🛠️ Common Use Cases:
- Security Patches: Forcing a safe version of a sub-dependency.
- Forking: Replacing an existing dependency with a custom fork.
- Consistency: Ensuring the same version of a package is used across all modules.
Scoped Override
If you only want to force a version for one specific parent package:
{
"overrides": {
"awesome-typescript-loader": {
"typescript": "4.6.2"
}
}
}
Global Override
To force a version across the entire tree, regardless of the parent:
{
"overrides": {
"lodash": "^4.17.21"
}
}
It is going to replace every lodash in your project tree with the version above.
The Dependency Variable ($)
If you already have the package as a direct dependency, use the $ sign to sync the sub-dependency version to your own. This creates a reusable configuration that stays in sync:
{
"devDependencies": {
"typescript": "~4.6.2"
},
"overrides": {
"awesome-typescript-loader": {
"typescript": "$typescript"
}
}
}
The "." (Dot) Match Override
It means apply this override to the package itself
{
"overrides": {
"eslint": {
".": "8.56.0",
"chalk": "5.2.0"
}
}
}
Eslint itself is replaced with the version shown above: 8.56.0. The dependency residing inside eslint will be force to use v.5.2.0.
Helpful, when a package depends on an older version of itself.
Real Example
You have a project that uses:
- Express 3.21.2,
- an EOL framework,
But you’re getting CVE warnings about one of its subdependencies. Instead of forking and patching everything yourself, you can override the vulnerable dependency with a patched one.
{
"dependencies": {
"express": "3.21.2"
}
"overrides": {
"express": {
".": "npm:@neverendingsupport/express@3.21.4"
},
}
}
This tells npm to use the patched express version from a different source. It’s a nice way to apply security fixes without touching every dependent project.
🛠️ Try this when you need to debug subdependencies:
Check which versions are installed and where are they located
npm list body-parser
//shows tree structure with dependencies for a package
Run Npm explain
npm explain body-parser
//shows the resolution path - which package requested it, versions constraints, and why the version is being applied
Lockfiles
Sometimes overrides may not work or just don't get applied. For such cases, delete the lock file and all the dependencies, and re-install them once again. Make sure to backup the lockfile so that it can be restore later on, if needed.
Overrides:
- string --> overrides for global substitutions
- object --> overrides for targeted dependency tweaks
- "." --> overrides a package's own version or internal dependencies
