.npmrc support

Bun loads configuration options from .npmrc files, so you can reuse your existing registry and scope configuration.

Configuration is loaded in this order, with later sources overriding earlier ones:

  1. ~/.npmrc (or $XDG_CONFIG_HOME/.npmrc)
  2. ./.npmrc
  3. bunfig.toml (global, then project)
  4. BUN_CONFIG_REGISTRY / NPM_CONFIG_REGISTRY and BUN_CONFIG_TOKEN / NPM_CONFIG_TOKEN environment variables
  5. Command-line flags such as --registry

Credentials in .npmrc (//<registry>/:_authToken, etc.) apply no matter where you set the registry URL itself. See how credentials are matched.

Values may reference environment variables. Bun replaces ${NAME} with the variable's value, or leaves it as-is if the variable is unset. ${NAME?} becomes an empty string if unset.

As in npm, an unquoted value ends at the first ; or # (write \; or \# to keep the character), and whitespace around keys and values is dropped.

Auto-install reads the default registry, the scoped registries, and the registry credentials from .npmrc. The other options on this page apply to bun install and the other package manager commands only.

We recommend migrating your .npmrc file to Bun's bunfig.toml format, which supports more options, including Bun-specific ones.


Which files are read#

Bun reads up to two .npmrc files. Options in the later file override the earlier one:

  1. The user-level file. This is the file NPM_CONFIG_USERCONFIG (npm's userconfig option) points at when that variable is set; otherwise $XDG_CONFIG_HOME/.npmrc if it exists, otherwise $HOME/.npmrc.
  2. The .npmrc next to your project's root package.json.

Bun warns when one of these files exists but cannot be read. A command that installs or publishes packages then stops with an error. Other commands continue without its settings. A directory in the file's place gets the warning only.

A relative cache or cafile is relative to the .npmrc it is written in. A relative NPM_CONFIG_USERCONFIG is relative to the directory you run bun in. In all three, a leading ~/ is your home directory.

actions/setup-node with registry-url writes an .npmrc to $RUNNER_TEMP and exports NPM_CONFIG_USERCONFIG pointing at it, so bun publish reads the token from NODE_AUTH_TOKEN in that workflow the same way npm publish does.


Supported options#

Set the default registry#

Bun resolves packages from the default registry, which is npm's official registry (https://registry.npmjs.org/).

To change it, set the registry option in .npmrc:

.npmrc
registry=http://localhost:4873/

The equivalent bunfig.toml option is install.registry:

bunfig.toml
install.registry = "http://localhost:4873/"

Set the registry for a specific scope#

@<scope>:registry sets the registry for a specific scope:

.npmrc
@myorg:registry=http://localhost:4873/

The equivalent bunfig.toml option is to add a key in install.scopes:

bunfig.toml
[install.scopes]
myorg = "http://localhost:4873/"

A scope whose registry is empty uses the default registry. If --registry or an environment variable names another host than the config files do, a scope that has credentials of its own stays at the registry of the config files.

Configure options for a specific registry#

//<registry_url>/:<key>=<value> sets options for a specific registry:

.npmrc
# set an auth token for the registry
# ${...} is a placeholder for environment variables
//localhost:4873/:_authToken=${NPM_TOKEN}


# or you could set a username and password
# note that the password is base64 encoded
//localhost:4873/:username=myusername

//localhost:4873/:_password=${NPM_PASSWORD}

# or use _auth, which is your username and password
# combined into a single string, which is then base 64 encoded
//localhost:4873/:_auth=${NPM_AUTH}

Bun supports the following options:

  • _authToken
  • username
  • _password (base64 encoded password)
  • _auth (sent as written in a Basic header; npm's form is base64 encoded username:password, for example btoa(username + ":" + password))
  • email (accepted and ignored, as npm does)

The equivalent bunfig.toml option is to add a key in install.scopes:

bunfig.toml
[install.scopes]
# unlike _password in .npmrc, password is not base64 encoded; Bun encodes it for you
myorg = { url = "http://localhost:4873/", username = "myusername", password = "$NPM_PASSWORD" }

How credentials are matched#

Bun looks credentials up the way npm does. It takes the URL of the registry, without the scheme, and drops one path segment at a time until a key matches:

.npmrc
# for https://npm.example.com/team/a/ Bun tries, in this order:
//npm.example.com/team/a/:_authToken=...
//npm.example.com/team/:_authToken=...
//npm.example.com/:_authToken=...
  • All .npmrc files count as one: a key in ./.npmrc replaces the same key in ~/.npmrc.
  • :443 on an https URL and :80 on an http URL are the same as no port.
  • A credential you set next to the registry URL wins over these lines: token, username and password in bunfig.toml, user:password@ in a URL, and BUN_CONFIG_TOKEN / NPM_CONFIG_TOKEN. The one exception is a credential inside a registry= line of .npmrc, which a matching //host/ line replaces, as in npm.
  • A tarball on the same origin as its registry gets the registry's credentials. A tarball anywhere else gets a credential only if .npmrc has a line for that URL and the URL is https. Bun never sends a registry's credentials to another host.
  • publishConfig.registry in package.json follows the tarball rule: it gets a .npmrc line only over https, and environment variables are not expanded in it.
  • Bun sends credentials to http and https URLs only. A registry URL with another scheme, or without one, fails before any request.
  • A credential that contains a newline or a NUL byte is an error, wherever it comes from.

Controls how Bun installs workspace packages when they are available locally:

.npmrc
link-workspace-packages=true

The equivalent bunfig.toml option is install.linkWorkspacePackages:

bunfig.toml
[install]
linkWorkspacePackages = true

save-exact: Save exact versions#

Always saves exact versions without the ^ prefix:

.npmrc
save-exact=true

The equivalent bunfig.toml option is install.exact:

bunfig.toml
[install]
exact = true

ignore-scripts: Skip lifecycle scripts#

Prevents running lifecycle scripts during installation:

.npmrc
ignore-scripts=true

This is equivalent to using the --ignore-scripts flag with bun install. The environment variable NPM_CONFIG_IGNORE_SCRIPTS (or npm_config_ignore_scripts) also turns scripts off. See Lifecycle scripts.

Bun reads boolean options the way npm does: false, null, undefined and 0 turn an option off. Every other value turns it on, including an empty one, 1 and True.

dry-run: Preview changes without installing#

Shows what Bun would install without installing anything:

.npmrc
dry-run=true

The equivalent bunfig.toml option is install.dryRun:

bunfig.toml
[install]
dryRun = true

cache: Configure cache directory#

Set the cache directory path, or disable caching:

.npmrc
# set a custom cache directory
cache=/path/to/cache

# or disable caching
cache=false

The equivalent bunfig.toml option is install.cache:

bunfig.toml
[install.cache]
# set a custom cache directory
dir = "/path/to/cache"

# or disable caching
disable = true

ca and cafile: Configure CA certificates#

Configure custom CA certificates for registry connections:

.npmrc
# single CA certificate
ca="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"

# multiple CA certificates
ca[]="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
ca[]="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"

# or specify a path to a CA file
cafile=/path/to/ca-bundle.crt

If both are set, only cafile is used. A ca or cafile in a later .npmrc or in bunfig.toml, or --ca / --cafile on the command line, replaces both.

omit and include: Control dependency types#

Control which dependency types Bun installs:

.npmrc
# omit dev dependencies
omit=dev

# omit multiple types
omit[]=dev
omit[]=optional

# include specific types (overrides omit)
include=dev

Valid values: dev, peer, optional

install-strategy and node-linker: Installation strategy#

Control how Bun lays out packages in node_modules. For compatibility with other package managers, Bun accepts both npm's install-strategy and pnpm/yarn's node-linker. See isolated installs for how the hoisted and isolated layouts differ.

npm's install-strategy:

.npmrc
# flat node_modules structure (default)
install-strategy=hoisted

# symlinked structure
install-strategy=linked

pnpm/yarn's node-linker:

node-linker controls the installation mode. Bun accepts values from both pnpm and yarn:

ValueDescriptionAccepted by
isolatedSymlinked structure with isolated dependenciespnpm
hoistedFlat node_modules structurepnpm
pnpmSymlinked structure (same as isolated)yarn
node-modulesFlat node_modules structure (same as hoisted)yarn
.npmrc
# symlinked/isolated mode
node-linker=isolated
node-linker=pnpm

# flat/hoisted mode
node-linker=hoisted
node-linker=node-modules

public-hoist-pattern and hoist-pattern: Control hoisting#

Control which packages Bun hoists to the root node_modules:

.npmrc
# packages matching this pattern will be hoisted to the root
public-hoist-pattern=*eslint*

# multiple patterns
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*

# control general hoisting behavior
hoist-pattern=*

# isolated linker only: disable the node_modules/.bun/node_modules fallback,
# so store packages only resolve declared deps (plus the root node_modules).
# Hoisted installs ignore this setting.
hoist=false