Skip to content
RegistryPublishing

Publishing Packages

Your account’s main registry hosts your private packages. Every package published to it must be scoped to your account slug — for example, an account with the slug acme publishes packages named @acme/utils, @acme/app, and so on.

The registry speaks the npm registry protocol, so you can publish with whichever package manager you already use — vlt, npm, pnpm, yarn, or bun.

Configure your project

Map your account scope to your registry so installs and publishes for that scope go to vlt:

Terminal
$ vlt config set scoped-registries=@acme=https://registry.vlt.io/acme/main/

This stores the mapping in your project’s vlt.json. See Working with Named Registries for the full range of registry configuration options.

If you’re using npm, the equivalent .npmrc entry is:

.npmrc
@acme:registry=https://registry.vlt.io/acme/main/

You’ll also need to authenticate — see Authentication & Tokens. The dashboard’s Setup page (under Packages) generates both steps for your account, tailored to your package manager.

Publish

From your package directory:

Terminal
$ vlt publish

Your package manager packs the package into a tarball and uploads it along with its manifest. If you’re using the vlt client, see the vlt publish command reference for options like --tag and --publish-directory.

The registry validates every publish:

  • The package name must be scoped to your account: @acme/utils publishes, but an unscoped name like utils, or a name under someone else’s scope like @other-team/utils, is rejected with a 403 Forbidden error.
  • The name and version in the request, the manifest, and the tarball’s package.json must all agree, which protects consumers against manifest confusion.
  • The tarball’s integrity hash is recomputed and verified on the server.
  • Tarballs are limited to 100 MB by default.

Versions are immutable

Exactly one version is published at a time, and once a version is published it can never be replaced. Publishing an existing version again fails with a conflict error. If you unpublish a version, that version number is permanently reserved and cannot be reused — publish a new version instead.

Dist-tags

If you don’t specify a tag, a publish updates latest. Use a tag to publish pre-releases without affecting the default install:

Terminal
$ vlt publish --tag=beta

Tags can only reference versions that exist, and the standard npm dist-tag endpoints are supported for listing, adding, and removing tags.

Two-factor authentication

By default, accounts require a one-time password (OTP) for publishes and other package writes made with a personal token. When the registry asks for it, your client opens a browser or prompts for the code from your authenticator app.

Service tokens are not subject to the OTP prompt, which is what makes unattended publishes from CI possible. Account owners can adjust the two-factor requirement in the account’s security settings.

Publishing from CI

Create a service token with the package:write privilege (see Authentication & Tokens) and provide it to the client through the environment:

Terminal
VLT_TOKEN_https_registry_vlt_io_acme_main="<service token>" vlt publish

See Authentication — CI for how token environment variables are named.

Deprecating and unpublishing

Deprecation and unpublish follow the standard npm protocol, so npm deprecate and npm unpublish work against your registry. Deprecating a version attaches a warning message that installers display; it can be reversed by deprecating again with an empty message. Unpublishing removes a version (or an entire package), and as noted above, unpublished version numbers can never be reused.

Package visibility

Visibility is controlled at the account level: packages on a private account’s main registry are readable only by members of that account. There is no per-package --access setting.