Description
Is there an existing issue for this?
- I have searched the existing issues
This issue exists in the latest npm version
- I am using the latest npm
Current Behavior
Using a local registry, where all package versions use local paths, and installing with --install-links
, packages that are referenced multiple times get deduped even though they are different versions (in this case, have a different local path).
Consider package copy-props 2.0.5
.
This package has the following truncated dependency tree, where there are two versions of is-plain-object
used, 2.0.4
and 5.0.0
:
copy-props (2.0.5)
├── each-props (1.3.2)
│ ├── is-plain-object (2.0.4)
│ └── ...
└── is-plain-object (5.0.0)
Normally this has the following tree when installed via the NPM registry, where you can see both version 2.0.4
and 5.0.0
of is-plain-object
present in node_modules
:
.
├── node_modules
│ ├── array-each
│ │ └── ...
│ ├── array-slice
│ │ └── ...
│ ├── copy-props
│ │ └── ...
│ ├── each-props
│ │ ├── node_modules
│ │ │ └── is-plain-object <------------- 2.0.4
│ │ │ └── ...
│ │ └── ...
│ ├── for-in
│ │ └── ...
│ ├── for-own
│ │ └── ...
│ ├── isobject
│ │ └── ...
│ ├── is-plain-object <------------------- 5.0.0
│ │ └── ...
│ └── object.defaults
│ └── ...
└── ...
However, if you create your own local registry with all of these packages available, and use local paths to define the package version in the list of dependencies in package.json, and if you use --install-links
option, the resulting node_modules
structure is as follows, where it's missing version 2.0.4
of is-plain-object
:
.
├── node_modules
│ ├── array-each
│ │ └── ...
│ ├── array-slice
│ │ └── ...
│ ├── copy-props
│ │ └── ...
│ ├── each-props <- ⚠️ no inner node_modules, no is-plain-object 2.0.4
│ │ └── ...
│ ├── for-in
│ │ └── ...
│ ├── for-own
│ │ └── ...
│ ├── isobject
│ │ └── ...
│ ├── is-plain-object <-------------------------- 5.0.0
│ │ └── ...
│ └── object.defaults
│ └── ...
└── ...
In the above example, here is an excerpt from various package.json
files in the local registry:
local-repo/copy-props/package.json
:
{
"dependencies": {
"each-props": "/path/to/local-repo/each-props",
"is-plain-object": "/path/to/local-repo/is-plain-object@5"
}
}
local-repo/each-props/package.json
:
{
"dependencies": {
"is-plain-object": "/path/to/local-repo/is-plain-object@2",
"object.defaults": "/path/to/local-repo/object.defaults"
}
}
If the user does NOT use --install-links
, both versions 2.0.4 and 5.0.0 are installed.
Expected Behavior
Regardless if using --install-links
or not, when using npm install with a local registry using local paths, the output node_modules
files structure should be the same (except with installed files instead of symlinks).
Steps To Reproduce
- Download, unzip, and chdir into test.zip
- Delete
broken/node_modules/
andbroken/package-lock.json
- In all of the 11
broken/**/package.json
files (includingbroken/package.json
) replace all occurances ofC:/Users/Dan/test/broken
with$(pwd)/broken
- cd into
broken
and runnpm --install-links install
- Navigate to the newly created
node_modules
and notice the missingis-plain-object
version2.0.4
Environment
- npm: 11.3.0
- Node.js: v24.2.0
- OS Name: Windows 10
- System Model Name:
- npm config:
; node bin location = C:\Program Files\nodejs\node.exe
; node version = v24.2.0
; npm local prefix = C:\Users\Dan\test\broken
; npm version = 11.3.0
; cwd = C:\Users\Dan\test\broken
; HOME = C:\Users\Dan
This also happens on Guix System (Linux) with NPM 10.9.2