cli
cli copied to clipboard
[BUG] `npm install --production` can delete local workspaces if they've been renamed
Is there an existing issue for this?
- [x] I have searched the existing issues
This issue exists in the latest npm version
- [x] I am using the latest npm
Current Behavior
If you rename a local workspace package that's a dev dependency of another local workspace, and add it as a new dev dependency without removing the old one, this can cause lockfile/symlink cruft which can then cause --production installs to fully delete the local workspace directory.
Expected Behavior
Renaming a local workspace package should never cause --production installs to delete local workspaces. Ideally:
- Obsolete local symlinks should be cleaned up, e.g. if
bargets renamed tobaz, thennode_modules/barshould get deleted. - Related to the above, depending on an obsolete local symlink (e.g.
"dependencies": {"bar": "1.0.0"}) should cause an error. - Local workspaces should not have
"dev": trueset, even if they are dev deps of another workspace. This seems to get set when there are 2+ local symlinks for a package, and is likely what causes--productionto delete things.
If any of the above are not feasible to implement, then npm ls or similar commands should alert users to these sorts of lockfile / tree inconsistencies.
Steps To Reproduce
Given
package.json
{
"workspaces": ["workspaces/*"]
}
workspaces/foo/package.json
{
"name": "foo",
"version": "1.0.0",
"private": true
}
workspaces/bar/package.json
{
"name": "bar",
"version": "1.0.0",
"private": true
}
Run
npm install --save-dev bar -w workspaces/foo- Edit
workspaces/bar/package.jsonand change thenametobaz npm install --save-dev baz -w workspaces/foo
Alternatively, just check out this repo and run npm install which will get you to this point.
Observe
- There are now symlinks at
node_modules/barandnode_modules/baz package-lock.jsoncontains:"workspaces/bar": { "name": "baz", "version": "1.0.0", "dev": true },npm lsreports no problems (though it does indicate it was dedup'ed)npm install --productiondeletesworkspaces/bar💥
Additional Notes
- This only happens with
devDependencies - The lexicographical order of the old and new package names seems to matter. I.e. going from
bar->bazcauses the issue. Going frombaz->bardoes not; you still get two symlinks, but"dev": truewon't get set in the lockfile, so a--productioninstall won't delete the workspace.
Environment
- npm: 11.5.2
- Node.js: 22.14.0
- OS Name: Mac OS Sequoia 15.6
- System Model Name: Macbook Pro
- npm config:
; copy and paste output from `npm config ls` here