npm install link

A safer and enhanced version of npm link.
Why is npm link unsafe? Read the blog post.
Already a sponsor? Join the discussion in the Development repo!
- Dependency package
The package getting linked. This is usually a library.
- Consuming package
The project you want to link the _Dependency package_ as a dependency of. This is usually an application.
consuming-package/node_modules/dependency-package → dependency-package
From the _Consuming package_ directory, link the _Dependency package_:
``sh`
npx link
This creates a symbolic link inside the node_modules of _Consuming package_, referencing the _Dependency package_.
> 🛡️ Secure linking
>
> Unlike npm link, it doesn't install the _Dependency package_ globally or re-install project dependencies.
Using symbolic links may not replicate the exact environment you get from a standard npm install. This discrepancy primarily arises from symlinked packages retaining their development node_modules directory. This can lead to issues, especially when multiple packages depend on the same library.
Here's an example
In a production environment, npm install detects common dependencies and installs only one instance of a shared dependency. However, when there's a symbolic link to the development directory of a dependency, separate copies of those dependencies are resolved from the development node_modules.
Let's say there's an _App A_ with a dependency on _Package B_, and they both depend on _Library C_:
- Production environment
npm install detects that both _App A_ and _Package B_ depends on _Library C_, and only installs one copy of _Library C_ for them to share.
- Symbolic link environment
_App A_ has its copy of _Library C_, and _Package B_ also has its development copy of _Library C_—possibly with different versions. Consequently, when you run the application, it will load two different versions of _Library C_, leading to unexpected outcomes.
_Publish mode_ helps replicate the production environment in your development setup.
#### Setup instructions
1. In the _Dependency package_, run npm pack to create a tarball:
`sh`
cd dependency-package-path
npm pack
This generates a tarball (.tgz) file in the current directory. Installing from this simulates the conditions of a published package without actually publishing it.
> Tip: You can skip this step if this dependency is already installed from npm and there are no changes to the dependency's package.json
2. In the _Consuming package_
1. Install the Dependency tarball from _Step 1_
`sh`
npm install --no-save
This sets up the same node_modules tree used in a production environment.
2. Link the _Dependency package_
`sh`
npx link publish
This creates hard links in node_modules/dependency to the specific publish assets of the _Dependency package_.
Why hard links instead of symbolic links?
Another issue with the symlink approach is that Node.js, and popular bundlers, looks up the node_module directory relative to a module's realpath rather than the import path (symlink path). By using hard links, we can prevent this behavior and ensure that the node_modules directory is resolved using the production tree we set up in _Step 2_.
4. Start developing!
Any changes you make to the _Dependency package_ will be reflected in the node_modules directory of the _Consuming package_.
> Note: If the _Dependency package_ emits new files, you'll need to re-run npx link publish to create new hard links.
$3
Create a link.config.json (or link.config.js) configuration file at the root of the _Consuming package_ to automatically setup links to multiple _Dependency packages_.
Example _link.config.json_:
`json5`
{
"packages": [
"/path/to/dependency-path-a",
"../dependency-path-b",
],
}
The configuration has the following type schema:
`ts
type LinkConfig = {
// Whether to run npx link on dependency packages with link.config.json
deepLink?: boolean
// List of dependency packages to link
packages?: string[]
}
`
> Note: It's not recommended to commit this file to source control since this is for local development with local paths.
To link the dependencies defined in link.config.json, run:`sh`
npx link
By default, npx link only links packages in the _Consuming package_. However, there are cases where the _Dependency packages_ also needs linking setup.
Deep linking recursively runs link on every linked dependency that has a link.config.json file.
Enable with the --deep flag or deepLink property in link.config.json.
`sh`
npx link --deep
is complicated and dangerous to use. And npx link offers more features such as _Publish mode_.$3
Run npm install and it should remove them.npm install enforces the integrity of node_modules by making sure all packages are correctly installed. Reverting the links is a side effect of this.$3
You must use npx v7 or higher. Check the version with
npx -v.In the obsolete npx v6, local binaries take precedence over npm modules so
npx link can point to the native link/ln command:
`
$ npx link
usage: ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file [target_file]
ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file ... target_dir
link source_file target_file
`To work around this, install
link globally first:
`sh
$ npm i -g link
$ npx link
`Related
npx ci - A better npm ci`.