Install via Docker

docker run -d --name verdaccio \
    --restart unless-stopped \
    -p 127.0.0.1:4873:4873 \
    -v verdaccio-storage:/verdaccio/storage \
    -v ./conf:/verdaccio/conf \
    verdaccio/verdaccio:6

Or with npm directly:

npm install -g verdaccio
verdaccio        # runs on :4873, config at ~/.config/verdaccio/config.yaml

The config.yaml

# conf/config.yaml
storage: /verdaccio/storage
plugins: /verdaccio/plugins

web:
  title: Internal Packages
  primary_color: "#4f46e5"

auth:
  htpasswd:
    file: /verdaccio/storage/htpasswd
    max_users: 100

# Where to proxy unknown packages
uplinks:
  npmjs:
    url: https://registry.npmjs.org/
    timeout: 30s
    cache: true

# Package access rules
packages:
  '@mycompany/*':
    access: $authenticated
    publish: $authenticated
    unpublish: $authenticated
    # No proxy — these are internal-only

  '**':
    access: $all
    publish: $authenticated
    unpublish: $authenticated
    proxy: npmjs      # everything else falls through to public npm

listen: 0.0.0.0:4873
log: { type: stdout, format: pretty, level: info }

# Optional — persistent JWT tokens (so logins survive a restart)
security:
  api:
    jwt:
      sign:
        expiresIn: 90d

Restart Verdaccio. The web UI is at http://<host>:4873; sign in with npm adduser --registry http://<host>:4873 to create the first user.

Reverse proxy

# Caddy
npm.example.com {
    reverse_proxy 127.0.0.1:4873
    request_body { max_size 100MB }
}

Point clients at the public URL after this.

Use it as a developer

# Tell npm to use Verdaccio for everything
npm config set registry https://npm.example.com

# Or just for @mycompany packages, and stay on public npm for the rest
npm config set @mycompany:registry https://npm.example.com

# Log in
npm adduser --registry https://npm.example.com
# Prompts for username, password, email; saves token to ~/.npmrc

Publish an internal package

cd my-shared-lib

# package.json must scope to @mycompany
# {
#   "name": "@mycompany/utils",
#   "version": "1.0.0"
# }

npm publish

The package lands in Verdaccio, visible in the web UI under @mycompany/utils. Other team members install with npm install @mycompany/utils from their normal workflow.

The proxy behavior

When a client requests a package Verdaccio hasn't seen:

  1. Verdaccio asks the configured uplink (npmjs.org).
  2. Downloads the package tarball + metadata.
  3. Caches both locally.
  4. Serves to the client.

Subsequent installs of the same version are served from cache. Useful for offline CI / restricted networks / faster repeat installs in a team.

Authentication options

Beyond the bundled htpasswd:

  • LDAPverdaccio-auth-ldap
  • GitHub OAuthverdaccio-github-oauth
  • GitLabverdaccio-gitlab
  • OIDC / Generic OAuthverdaccio-openid for Authentik / Keycloak (see Authentik tutorial)

Install via npm into the Verdaccio container, reference in auth:.

Tokens for CI

Generate a read-only or publish token for CI:

npm token create --read-only
# Output: npm_********

# In CI:
echo "//npm.example.com/:_authToken=npm_********" >> ~/.npmrc
npm install

Tokens are revocable from the web UI; rotate per-CI-account as needed.

Storage management

The default file storage backend keeps everything under /verdaccio/storage/:

/verdaccio/storage/
    htpasswd                            # bcrypt'd user creds
    @mycompany/
        utils/
            package.json
            utils-1.0.0.tgz
            utils-1.0.1.tgz
    react/                              # cached from npmjs
        package.json
        react-18.0.0.tgz
        react-18.1.0.tgz

For larger registries, swap the storage backend (S3, MinIO via plugin). For most teams, file storage is fine; restic backups on the directory covers it.

Verdaccio for other ecosystems

The npm registry shape is closer to "private store + cache for packages" than the npm CLI specifically. Equivalents exist for:

  • Maven / Gradle (Java) — Reposilite (Kotlin, single-binary), Nexus Repository (heavier), JFrog Artifactory (commercial).
  • PyPI (Python) — pypiserver, devpi, Bandersnatch (mirror).
  • RubyGems — Geminabox.
  • Docker / OCI — Distribution (the upstream Docker registry), Harbor (with auth, scanning), Cloudsmith / Artifactory for commercial.
  • Helm — ChartMuseum, or use the OCI registry pattern.
  • Multi-format — Nexus, Artifactory, Cloudsmith handle all of the above in one product (commercial).

For just npm + a small team, Verdaccio is the right size in 2026. For a polyglot fleet with serious package management requirements (vulnerability scanning, signed artifacts, multi-region replication), graduate to Nexus or a hosted service like Cloudsmith.

When Verdaccio isn't the right tool

  • For high-availability registries serving an entire enterprise, Verdaccio's single-node story doesn't scale.
  • For per-package vulnerability scanning + license tracking, look at Snyk + a heavier registry.
  • For OCI / container images, use a dedicated container registry.

For "we want our internal JavaScript packages on infrastructure we control, plus a faster cache for public npm," Verdaccio installs in under five minutes and stays out of the way.