Skip to content

[BUG] install with --install-links and local path dependencies "dedups" packages even when the local path is different #8364

Open
@Daniel-Khodabakhsh

Description

@Daniel-Khodabakhsh

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

  1. Download, unzip, and chdir into test.zip
  2. Delete broken/node_modules/ and broken/package-lock.json
  3. In all of the 11 broken/**/package.json files (including broken/package.json) replace all occurances of C:/Users/Dan/test/broken with $(pwd)/broken
  4. cd into broken and run npm --install-links install
  5. Navigate to the newly created node_modules and notice the missing is-plain-object version 2.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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bugthing that needs fixingNeeds Triageneeds review for next steps

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions