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.

A proxy registry sits between your clients and the public registry: it serves packages it hosts and, for anything it does not, fetches from an upstream and caches the tarball. That single indirection is what lets one host serve both your private scope and the public dependencies your packages need, with integrity still verified against the lockfile. Verdaccio is the common self-hosted choice because it implements this proxy behavior with a simple configuration and runs anywhere a Node process or a container can.

The reason teams reach for Verdaccio rather than a paid private registry is usually control or cost: private npm packages require a paid plan, while Verdaccio lets you host private packages for free on infrastructure you own, and it doubles as a caching layer that speeds installs and insulates CI from public-registry outages. The trade-off is that you now run and secure the registry, which is the operational cost that comes with the control.

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.

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

# config.yaml
uplinks:
  npmjs:
    url: https://registry.npmjs.org/
packages:
  '@acme/*':
    access: $authenticated
    publish: $authenticated
    proxy: npmjs
  '**':
    access: $all
    proxy: npmjs
auth:
  htpasswd:
    file: ./htpasswd
    max_users: -1   # disable open self-registration
docker run -d -p 4873:4873 -v $PWD/config.yaml:/verdaccio/conf/config.yaml verdaccio/verdaccio

Point only your scope at Verdaccio (npm config set @acme:registry http://localhost:4873), and the uplink proxies and caches everything else.

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.
  • Require authentication for both access and publish on your private scope.
  • Disable open self-registration (max_users: -1) and create users deliberately.
  • Keep uplink proxying so public dependencies resolve and cache through one host.
  • Back up the storage volume — it holds the only copy of your private tarballs.

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.

Hardening Verdaccio for shared use

A Verdaccio instance that is safe on a developer's laptop 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. 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.

Hardening Verdaccio for shared use A Verdaccio instance that is safe on a developer's laptop is not automatically safe as a team registry. Hardening Verdaccio for shared use A Verdaccio instance that is safe on a developer's laptop is not automatically safe as a team registry.
Hardening Verdaccio for shared use — the core idea of this section at a glance.

A common and painful 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. The private tarballs it hosts exist nowhere else, unlike the public packages it merely caches, so protecting the storage is protecting the only copy of your internal code. Hardening it properly — TLS, real authentication, deliberate user creation, and backed-up persistent storage — is what turns Verdaccio from a quick local experiment into a registry a team can depend on.

Verdaccio versus a hosted private registry

Self-hosting Verdaccio buys control and costs operations, so the choice against a hosted option comes down to what you need. Verdaccio gives you full control over storage, authentication, 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 organization, 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 requirements and team size. A team that needs an air-gapped or strictly-controlled resolution path, or that wants to cache the public registry for availability and install speed, is well served by Verdaccio despite the operational overhead. A team that just needs private scoped packages with minimal fuss is usually better off on a hosted registry that handles the infrastructure. The access-control model — scoped tokens, restricted access, provenance — applies either way; only who runs the server changes. Being clear about whether you have a genuine control or caching requirement, versus simply wanting private packages, is what makes the choice between self-hosting and a hosted registry a deliberate one rather than a default.

Publishing and consuming through Verdaccio

Once Verdaccio is running and your scope is pointed at it, publishing and consuming private packages work like any registry, with the scope routing handling the split between private and public. To publish, authenticate to Verdaccio and run a normal npm publish; the package lands in Verdaccio's storage under your scope and is served to authenticated consumers. To consume, the same scope mapping means npm install @acme/pkg resolves from Verdaccio while public dependencies proxy through its uplink.

Publish + consume Authenticate, publish to your scope, install normally. adduser + publish private scope scope mapped install normally uplink proxies public deps cached
Scope routing splits private packages from proxied public ones through one host.
# Authenticate and publish a scoped package to Verdaccio
npm adduser --registry http://localhost:4873
npm publish --registry http://localhost:4873
# Consumers with the scope mapped install normally
npm install @acme/pkg

For CI, the token from npm adduser is stored as a secret and referenced in .npmrc the same way a hosted registry's token would be, so a pipeline publishes and installs against Verdaccio without a developer's interactive login. The key operational point is that Verdaccio's storage now holds the only copy of these private packages — the public ones it merely caches from upstream — so the publish workflow and the storage backup are two halves of the same responsibility. A published private package exists nowhere else until you back up the volume that holds it.

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.

Does Verdaccio replace the public npm registry?

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

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, require authentication to publish on your private scope, and back up the storage — it holds the only copy of your private tarballs.

Verdaccio or a hosted private registry?

Verdaccio for full control, an air-gapped resolution path, or public-registry caching, accepting the ops burden. A hosted registry (GitHub Packages, npm org) when you just need private scoped packages with minimal maintenance.

How do I publish a private package to Verdaccio?

Authenticate with npm adduser --registry http://your-verdaccio and run npm publish against it. With your scope mapped to Verdaccio, consumers install the package normally while public dependencies proxy through its uplink. Back up the storage — it holds the only copy.

Related

Private Registries and Access Control