Skip to content

npm registry ​

ReleaseDesk includes an npm-compatible registry for publishing and installing packages with the stock npm, pnpm, yarn and bun clients. Tarballs live in the same storage backend as your artifacts (disk or S3/R2).

The registry is off by default. Enable it with RD_NPM_ENABLED=true. It is served either at the root of a dedicated host (RD_NPM_HOST, for example npm.example.com) or, without extra DNS, under /npm/ on the dashboard origin. RD_NPM_MAX_PUBLISH_BYTES caps the publish body (default 100 MB).

Packages are always scoped. The scope is the slug of the organization that owns the package, so @acme/ui belongs to the org acme and no other org can publish into that scope. Unscoped names and a few reserved scopes are rejected.

Tokens ​

Create an API token under Settings → Tokens with npm:read to install private packages, plus npm:publish to publish. Leave App on All apps. Public packages can be read anonymously.

npm login is not supported; it returns a message pointing here. Use a token instead.

Configure clients ​

Pin the scope to ReleaseDesk so it can never resolve to registry.npmjs.org (this prevents dependency confusion). Put this in the project or user .npmrc:

ini
@acme:registry=https://npm.example.com/
//npm.example.com/:_authToken=${RD_TOKEN}

Without a dedicated host, use the path prefix on both lines:

ini
@acme:registry=https://releasedesk.example.com/npm/
//releasedesk.example.com/npm/:_authToken=${RD_TOKEN}
ClientSetup
npm, pnpmThe .npmrc above.
yarn berryIn .yarnrc.yml: npmScopes: { acme: { npmRegistryServer: "https://npm.example.com", npmAuthToken: "${RD_TOKEN}" } }
bunThe .npmrc above, or [install.scopes] in bunfig.toml: "@acme" = { url = "https://npm.example.com/", token = "$RD_TOKEN" }

Check the setup with npm ping --registry <url> and npm whoami --registry <url>.

Publish ​

sh
npm publish

Set "publishConfig": { "registry": "https://npm.example.com/" } in package.json, or pass --registry. Rules:

  • Versions are immutable. Publishing an existing version returns 409, and an unpublished version number is reserved forever.
  • A prerelease (1.0.0-beta.1) must be published with --tag. latest is only set by a stable publish without --tag.
  • Integrity is computed server-side; the tarball's package.json must match the published name and version.

Dist-tags, deprecate, unpublish ​

sh
npm dist-tag add @acme/ui@1.2.0 next
npm dist-tag rm @acme/ui next          # latest cannot be removed
npm deprecate @acme/ui@1.1.0 "use 1.2.0"
npm unpublish @acme/ui@1.1.0           # hidden, tarball returns 404

Unpublishing a whole package is restricted to org admins. All publish and management actions are written to the audit log.

GitHub Actions ​

yaml
- uses: actions/setup-node@v4
  with:
    node-version: 22
    registry-url: https://npm.example.com/
    scope: "@acme"
- run: npm publish
  env:
    NODE_AUTH_TOKEN: ${{ secrets.RD_NPM_TOKEN }}

Dashboard ​

Packages appear under Packages: versions (ordered by semver precedence), dist-tags, deprecation status, install snippet and visibility (private or public). Deprecate and unpublish are done from the CLI for now.

Not supported ​

Search, npm audit data, provenance, and proxying registry.npmjs.org.