A private npm proxy sits between your builds and the public registry, caches what passes through, and gives you one place to apply policy and keep logs. It helps with availability, control and dependency confusion. It does not make packages safe by itself, so pair it with a lockfile and review.
What does a proxy actually do?
Open source registries such as Verdaccio describe the idea as an uplink: a link with an external registry that provides access to external packages. Your clients ask the proxy, the proxy merges its own packages with the upstream metadata, and by default can cache remote tarballs in its storage. Uplink settings include timeouts, cache lifetime, proxy settings for the outbound connection and optional authorization headers.
The effect is that your developers and CI talk to one host you control. If the public registry has a bad hour, cached packages still install. If you need to know who fetched what, the logs are yours.
How do clients get pointed at it?
The npm configuration docs describe the registry setting and the ability to bind a scope to a registry. The scope documentation says you can associate a scope with a registry, so packages under your company scope always come from your server. A typical project file sets the default registry to the proxy and the company scope to your internal registry, committed so every developer and CI job inherits it.
That scope binding matters for dependency confusion. If an internal package name is also free on the public registry, a misconfigured client may fetch the public one. Binding the scope removes the ambiguity, and reserving the scope name on the public registry closes the other side.
What does the lockfile add?
The package-lock documentation says each entry records a resolved location and an integrity value, described as a standard Subresource Integrity string for the artifact. It also notes that registry.npmjs.org in a resolved URL is a magic value meaning the currently configured registry. So the same lockfile works against a mirror, and the integrity hash still has to match. A mirror that serves altered content will fail the install.
What does a proxy not do?
Caching a malicious package faithfully is still caching a malicious package. A proxy is a control point, not a verdict. You need rules on top: block names that are close to known packages, hold new versions for a short window before they are allowed, and disable install scripts in CI where you can. The npm docs describe an ignore-scripts setting that stops lifecycle scripts from running, with the caveat that commands explicitly meant to run a script still do.
Also remember the mirror becomes a high value target. Protect its admin interface, authenticate publish access, and back up its storage.
Constructed example
A company runs a proxy and sets its scope to the internal registry. A developer typos a dependency name, and the proxy, configured to block packages first published within the last week, refuses the install. The build fails loudly, which is the intended outcome.
What to do
- Choose a proxy that supports uplinks, caching, access control and logging.
- Commit a project level npm config that sets the default registry and binds your scope to the internal registry.
- Reserve your scope name on the public registry.
- Require lockfiles and use clean installs in CI so integrity values are enforced.
- Add policy at the proxy: new version hold, name similarity checks, deny lists.
- Run installs in CI with scripts disabled where builds allow it.
- Restrict who can publish and who can administer the proxy. Log and alert.
- Scan the dependency inventory regularly. Safeguard can generate SBOMs and scan dependencies, which fits behind a proxy as a second check.
Quick check
Does a private mirror stop dependency confusion?
It helps when internal scopes are bound to the internal registry, and your clients cannot reach the public registry directly for those names.
Will the lockfile still work through a mirror?
Yes. The integrity value is checked against the downloaded artifact, wherever it came from.
Sources
- Verdaccio uplinks documentation
- npm config documentation
- npm scope documentation
- package-lock.json documentation
Last reviewed: 18 October 2026.