Back to publishing & release Automate semantic versioning Publish to the npm registry Harden the supply chain

Setting Up Verdaccio as a Private Proxy Registry

You want internal packages hosted privately while public dependencies still resolve, without paying for a hosted registry. This page shows how to run Verdaccio as a private, caching proxy and point your workspace at it safely.

Exact symptoms and error messages

Before Verdaccio, internal packages have nowhere private to live, so teams resort to git URLs or publishing proprietary code publicly:

Exact symptoms and error messages Before Verdaccio, internal packages have nowhere private to live, so teams resort to git URLs or publishing proprietary Exact symptoms and error messages Before Verdaccio, internal packages have nowhere private to live, so teams resort to git URLs or publishing proprietary code publicly:
Exact symptoms and error messages — the core idea of this section at a glance.
npm error 402 Payment Required - publishing a private package requires a paid plan

You need a host you control that serves your scope and proxies everything else.

Root cause analysis

A proxy registry sits between your clients and the public registry: it serves packages it hosts, and for anything it does not, it fetches from upstream and caches the tarball. That single host can therefore satisfy both @acme/* and public dependencies, with integrity still verified against your lockfile.

Root cause analysis A proxy registry sits between your clients and the public registry: it serves packages it hosts, and for anything it doe Root cause analysis A proxy registry sits between your clients and the public registry: it serves packages it hosts, and for anything it does not, it fetches from upstream and cach
Root cause analysis — the core idea of this section at a glance.

A proxy registry works because npm's protocol is uniform: whether a package is yours or public, the client asks the configured registry for a manifest and a tarball. Verdaccio answers for packages it hosts and, for anything it does not, fetches from an upstream and caches the result. That single indirection is what lets one host serve both @acme/* and the entire public dependency graph, with integrity still verified against your lockfile.

The caching behavior also hardens your builds against upstream outages and package removals. Once Verdaccio has cached a public tarball, installs that need it succeed even if the public registry is unreachable or the version is later unpublished — a meaningful availability benefit for teams whose CI would otherwise fail on an upstream hiccup.

Resolution and configuration patch

Run Verdaccio and configure an uplink to the public registry plus access rules for your scope:

Resolution and configuration patch Run Verdaccio and configure an uplink to the public registry plus access rules for your scope: Resolution and configuration patch Run Verdaccio and configure an uplink to the public registry plus access rules for your scope:
Resolution and configuration patch — the core idea of this section at a glance.
# config.yaml
uplinks:
  npmjs:
    url: https://registry.npmjs.org/
packages:
  '@acme/*':
    access: $authenticated
    publish: $authenticated
    proxy: npmjs
  '**':
    access: $all
    proxy: npmjs
docker run -d -p 4873:4873 -v $PWD/config.yaml:/verdaccio/conf/config.yaml verdaccio/verdaccio

Lock down who can publish before you expose the registry to anyone. Verdaccio ships with open registration by default, which is fine locally but dangerous shared:

auth:
  htpasswd:
    file: ./htpasswd
    max_users: -1   # -1 disables self-registration; add users manually
packages:
  '@acme/*':
    access: $authenticated
    publish: $authenticated
    unpublish: $authenticated

With max_users: -1, new accounts are created deliberately rather than by anyone who finds the URL, and requiring $authenticated for publish keeps the private scope from being overwritten by an anonymous client.

CLI validation and debug commands

CLI validation and debug commands CLI validation and debug commands in production JavaScript package workflows. CLI validation and debug commands CLI validation and debug commands in production JavaScript package workflows.
CLI validation and debug commands — the core idea of this section at a glance.
# Point only your scope at Verdaccio
npm config set @acme:registry http://localhost:4873
# Create a user and publish a scoped package
npm adduser --registry http://localhost:4873
npm publish --registry http://localhost:4873
# Confirm a public dep proxies through and caches
npm install lodash --registry http://localhost:4873

Prevention and CI guardrails

  • Require authentication for both access and publish on your private scope.
  • Restrict who can publish with Verdaccio's htpasswd or an auth plugin, not open registration.
  • Keep uplink proxying so public dependencies resolve and cache through one host.
  • Back up the Verdaccio storage volume — it holds the only copy of your private tarballs.
Prevention and CI guardrails Prevention and CI guardrails in production JavaScript package workflows. Prevention and CI guardrails Prevention and CI guardrails in production JavaScript package workflows.
Prevention and CI guardrails — the core idea of this section at a glance.

Hardening Verdaccio for shared use

A Verdaccio instance that is safe on localhost is not automatically safe as a team registry. Three things change when you share it: it needs TLS so tokens are not sent in the clear, it needs authentication that is not open self-registration, and it needs its storage volume backed up because it now holds the only copy of your private tarballs.

Shared-use hardening TLS, auth, and backups turn a dev instance into infrastructure. HTTPS reverse proxy tokens not in clear no self-registration deliberate users authenticated publish no anonymous writes backed-up storage only copy of tarballs
A shared Verdaccio needs the TLS, auth, and backup rigor of any code-holding service.

Put it behind a reverse proxy that terminates HTTPS, disable anonymous publish on your private scope, and treat the storage directory as production data with a backup schedule. A common mistake is running the container with an ephemeral volume — a restart then wipes every private package you published. The mental model is that a shared Verdaccio is infrastructure, not a dev convenience: it earns the same TLS, auth, and backup rigor you would give any service that holds code you cannot re-download from anywhere else.

Verdaccio versus a hosted registry

Self-hosting buys control and costs operations. Verdaccio gives you full control over storage, auth, and the resolution path, and it proxies the public registry so one host serves everything — but you own its uptime, TLS, backups, and upgrades. A hosted option (GitHub Packages, an npm org, a cloud artifact registry) removes that operational burden at the cost of some control and, sometimes, money.

Self-hosted vs hosted Verdaccio against a hosted private registry. Axis Verdaccio Hosted Control full vendor-bounded Ops burden you own it managed Best for air-gapped / caching low-fuss private
Self-hosting buys control; hosting removes the operational burden.

The decision usually comes down to team size and requirements. A team that needs an air-gapped or strictly-controlled resolution path, or that wants to cache the public registry for availability, is well served by Verdaccio despite the ops overhead. A team that just needs private scoped packages with minimal fuss is usually better off on a hosted registry. The access-control model — scoped tokens, restricted access, provenance — applies either way; only who runs the server changes.

Frequently Asked Questions

Does Verdaccio replace the public npm registry?

No — it proxies it. Verdaccio serves your private packages and forwards requests for public packages upstream, caching the results, so one host covers both.

Is Verdaccio safe to expose to the internet?

Only behind authentication and TLS. Restrict publish to authenticated users, put it behind a reverse proxy with HTTPS, and never allow anonymous publish on your private scope.

Is Verdaccio safe to expose beyond localhost?

Only with TLS, real authentication, and disabled self-registration. Put it behind an HTTPS reverse proxy, create users deliberately, and require authentication to publish on your private scope before any shared use.

What happens to my private packages if Verdaccio restarts?

They live in its storage volume. If that volume is ephemeral, a restart wipes them — Verdaccio holds the only copy of private tarballs. Use a persistent, backed-up volume and treat it as production data.

Verdaccio or a hosted registry — how do I choose?

Choose Verdaccio for full control, an air-gapped resolution path, or public-registry caching, accepting the ops burden. Choose a hosted registry when you just need private scoped packages with minimal maintenance.

Related

Private Registries and Access Control