npm link creates symlinks so you can test a local package in another project. By default it does not save the link to package.json. A file: dependency is different: it is written into package.json and the lockfile, points at a path on one machine, and should not be published to the public registry.
What npm link does
The npm docs describe a two step process. Running npm link in a package folder creates a symlink in the global folder pointing at that package. Running npm link with a package name in another project then symlinks it into that project's node_modules. Changes in the source folder show up immediately in the consumer.
Two caveats from the docs matter for security and reproducibility:
- Linked packages are not saved to package.json by default. The assumption is that a link stands in for a regular dependency, such as a registry version range, and you do not want the range replaced with a path on your laptop.
- To record a link as a new dependency, the docs suggest running install with the package-lock-only flag, or use link with save to write the file: reference.
What a file: dependency does
A file: entry names a path, for example a sibling folder. It is saved to package.json and the lockfile. The npm docs say this is helpful for local offline development and for tests that need npm installing without hitting an external server, but should not be used when publishing your package to the public registry.
Two more documented behaviors:
- Packages linked by local path do not get their own dependencies installed when you run npm install in the parent. You run install inside the local path.
- The install-links config changes how file: dependencies are installed: they are packed and installed as regular dependencies instead of creating a symlink. It has no effect on workspaces.
Side by side
| Question | npm link | file: dependency |
|---|---|---|
| Written to package.json | Not by default | Yes |
| Shared with teammates | No, it lives on your machine | Only if the path exists for them |
| In the lockfile | Not by default | Yes |
| Good for | Quick local iteration | Offline development and tests |
| Safe to publish | n/a | Not to the public registry |
Security and review angles
A linked or file-referenced package skips the registry. There is no publish date, no provenance, and no integrity from a registry tarball. That is fine for your own code. It is a gap if the folder is someone else's code that you cloned and did not review.
Symlinks also never ship in published npm packages, according to the npm publish docs, so a test that passes because of a link can fail for consumers. When a package is linked and bundled via bundleDependencies, the docs say the link is snapshotted to its current state at pack time.
A habit list
- Before committing, search package.json for file: references that should not be there.
- Check CI installs from a clean checkout. If it fails because a path does not exist, that is the signal.
- Remove global links when you finish with
npm ls -gas a guide. - Treat a cloned dependency folder like any third party code before linking it.
For lockfile review habits, see what to check in a lockfile diff.
Where Safeguard fits
Safeguard's dependency scanning and SBOM generation read lockfiles, so a file: reference shows up as a component with no registry source, which a policy can flag. A free scan is at https://gold.safeguard.sh/scan.
Quick check
Does npm link change package.json?
Not by default. The docs say links are not saved, so they can stand in for a regular dependency. Use link with save if you want the file: reference recorded.
Can I publish a package that depends on a file: path?
The npm docs say file: dependencies should not be used when publishing to the public registry, because the path will not exist for your users.
Sources
Last reviewed: 19 October 2026.