bun
Verified against bun 1.4.
Quick start
export VLT_TOKEN=<your token>Create bunfig.toml in your project root:
[install]registry = { url = "https://registry.vlt.io/acme/npm/", token = "$VLT_TOKEN" }
[install.scopes]acme = { url = "https://registry.vlt.io/acme/main/", token = "$VLT_TOKEN" }Then bun install as usual.
Because the token is a $VAR reference rather than a literal,
bunfig.toml is safe to commit.
What each block does
-
[install] registry— where all public npm packages come from. Points at your account mirror. -
[install.scopes]— per-scope overrides.acmeroutes@acme/*to yourmainregistry. The scope key works with or without the@, and[install.scopes.acme]as a table header is equivalent:[install.scopes.acme]url = "https://registry.vlt.io/acme/main/"token = "$VLT_TOKEN"
Use whichever reads better; all three forms are verified working.
Using .npmrc instead
bun also reads .npmrc, which is handy if you want one file that npm,
pnpm, deno and bun all share:
registry=https://registry.vlt.io/acme/npm/@acme:registry=https://registry.vlt.io/acme/main/
//registry.vlt.io/acme/npm/:_authToken=${VLT_TOKEN}//registry.vlt.io/acme/main/:_authToken=${VLT_TOKEN}In .npmrc the braced ${VLT_TOKEN} form is expanded.
If both files exist, bunfig.toml wins — but only on bun 1.4 and
newer. Bun 1.3 and earlier gave .npmrc priority, so a project
carrying both files changes behaviour across those versions. Pick one
file and delete the other.
Install from the npm mirror
bun add abbrevTo move an existing project onto the mirror:
rm -rf bun.lock node_modulesbun installInstall from your main registry
bun add @acme/my-packagePublic packages
Public packages on main install without a token — the URL alone is
enough, with no token:
[install.scopes]acme = { url = "https://registry.vlt.io/acme/main/" }Publish to main
bun publishbun resolves the publish registry from your scope config, so with the
[install.scopes] block above, @acme/my-package goes to main
automatically — no publishConfig needed.
Add --access public for a package anyone can install, and
--dry-run to preview.
With a personal token, every publish returns a one-time-password
challenge with a vlt.io URL — open it, approve, re-run. A service
token skips the prompt and is what you want in CI; see
CI & automation.
Gotchas
- Never omit the trailing slash. In bun 1.4, a registry URL that
has a path and no trailing slash silently loses its last path
segment —
https://registry.vlt.io/acme/npmresolves againsthttps://registry.vlt.io/acme/, and you get confusing 401s or 404s. This affectsbunfig.toml,.npmrcand[install.scopes]alike. Our URLs all have paths, so this matters every time. $VLT_TOKENinbunfig.toml,${VLT_TOKEN}in.npmrc. Getting this backwards produces a confusing401with a token that “looks” configured. An unset variable is sent as a literal string rather than failing, which looks the same from the registry’s side.- Quote the scope key if you include the
@."@acme" = { ... }is fine; unquoted@acme = { ... }is a hardSyntaxError: failed to load bunfigthat aborts the install. publishConfig.registryalone is not enough forbun publish. bun will find the URL but not the credentials, and fails witherror: missing authentication (runbunx npm login). Set the registry inbunfig.toml(or asregistry=in.npmrc) so the token travels with it.- Auth paths must match exactly. A host-wide
//registry.vlt.io/:_authToken=...works in npm and deno but not in bun — bun needs the full registry path, trailing slash included. - bun has no
logincommand. Authentication comes frombunfig.toml,.npmrc, or the environment.