Skip to content

install: let bunfig.toml registry take precedence over npm_config_registry - #34170

Closed
robobun wants to merge 3 commits into
mainfrom
farm/83d2fec9/bunfig-registry-precedence
Closed

robobun wants to merge 3 commits into
mainfrom
farm/83d2fec9/bunfig-registry-precedence

Conversation

@robobun

@robobun robobun commented Jul 14, 2026 •

Copy link
Copy Markdown
Collaborator

What does this PR do?

Fixes #34168

When npm_config_registry (or NPM_CONFIG_REGISTRY) is set in the environment, an explicit registry in bunfig.toml or .npmrc was silently ignored and the install failed with a confusing No version matching ... found error. The lowercase variant is injected into lifecycle-script environments by npm and pnpm and is commonly exported in shell profiles for mirrors, so it often leaks into bun install without the user asking for it.

Registry precedence is now:

  1. --registry
  2. BUN_CONFIG_REGISTRY
  3. bunfig.toml / .npmrc
  4. NPM_CONFIG_REGISTRY / npm_config_registry
  5. default (https://registry.npmjs.org/)

The npm-compat env vars become a fallback that only applies when no registry is explicitly configured. Bun's own BUN_CONFIG_REGISTRY keeps overriding the config files, so CI setups that force a mirror device-wide still have an env-var escape hatch (as does --registry).

The token env vars (BUN_CONFIG_TOKEN, NPM_CONFIG_TOKEN, npm_config_token) are intentionally unchanged: a token overlaid on the configured registry is the common auth-injection pattern and does not redirect traffic.

Reproduction

export npm_config_registry="https://registry.npmmirror.com"
cat > bunfig.toml << 'EOF'
[install]
registry = "https://registry.npmjs.org/"
EOF
bun add drizzle-kit@1.0.0-rc.4
# before: error: No version matching "1.0.0-rc.4" found for specifier "drizzle-kit"
# (the bunfig.toml registry was never contacted)

Implementation

Options::load in src/install/PackageManager/PackageManagerOptions.rs read BUN_CONFIG_REGISTRY, NPM_CONFIG_REGISTRY, and npm_config_registry after applying the bunfig/.npmrc config and unconditionally overwrote the default scope. Now the two npm-compat keys are skipped when the config set a non-empty registry URL.

An auth-only .npmrc (what npm login writes: //registry.npmjs.org/:_authToken=... with no registry= line) used to synthesize a default_registry with the default URL backfilled, which would have counted as an explicitly configured registry and dropped the env var fallback. The .npmrc parser now leaves the URL empty on that path, matching how bunfig represents auth-only registry config, and Options::load fills in the default as before.

Tests

Added to test/cli/install/bun-install-registry.test.ts:

  • registry from bunfig.toml takes precedence over npm_config_registry env vars: two local registries; asserts the manifest request reaches the bunfig registry and nothing reaches the env-var registry, for both spellings. Fails on bun 1.4.0, passes with this change.
  • npm_config_registry env var is used when bunfig.toml has no registry: pins the fallback behavior.
  • npm_config_registry env var is used when .npmrc only has auth for the default registry: the npm login setup; also asserts the saved token is not sent to the env var registry.

The existing registry override from a project .env ... test continues to cover BUN_CONFIG_REGISTRY overriding bunfig.toml and still passes.

Also documents the fallback in docs/pm/cli/install.mdx.


no test proof · iteration 0 · Platform-specific test(s) that do not run on this machine. Deferring to CI, which covers all platforms: test/cli/install/bun-install-registry.test.ts

…istry

An explicit registry in bunfig.toml or .npmrc now wins over the
npm-compat NPM_CONFIG_REGISTRY / npm_config_registry env vars, which
become a fallback for when no registry is configured. BUN_CONFIG_REGISTRY
and --registry keep overriding the config files.

Fixes #34168
@robobun

robobun commented Jul 14, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 12:06 PM PT - Jul 14th, 2026

❌ @robobun, your commit 3d91bfe has 3 failures in Build #72974 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 34170

That installs a local version of the PR into your bun-34170 executable, so you can run:

bun-34170 --bun

@coderabbitai

coderabbitai Bot commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Registry loading now preserves explicit bunfig.toml registries over npm registry environment variables, uses those variables when no registry is configured, and treats npmrc credential-only settings as registry URL-less. Documentation and tests cover these behaviors.

Changes

Registry precedence

Layer / File(s) Summary
Registry selection logic
src/ini/lib.rs, src/install/PackageManager/PackageManagerOptions.rs, docs/pm/cli/install.mdx
Explicit bunfig registries limit lookup to BUN_CONFIG_REGISTRY; otherwise npm registry environment variables are considered. npmrc auth-only configurations retain an empty registry URL until higher-level resolution. Documentation records the precedence rules.
Registry precedence tests
test/cli/install/bun-install-registry.test.ts, test/cli/install/npmrc.test.ts
Tests cover bunfig precedence, npm environment fallback without an explicit registry, auth-only .npmrc behavior, and empty URLs for credential-only npmrc configurations.

Suggested reviewers: jarred-sumner

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR fixes the reported precedence bug by making an explicit bunfig registry override npm_config_registry and preserving fallback behavior.
Out of Scope Changes check ✅ Passed The added docs, tests, and auth-only .npmrc handling all support the registry-precedence fix and do not appear unrelated.
Title check ✅ Passed The title clearly summarizes the main behavior change: registry precedence for bunfig.toml over npm_config_registry.
Description check ✅ Passed The description covers the PR purpose and includes reproduction plus tests, so the required verification details are present.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/pm/cli/install.mdx (1)

344-356: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Blanket statement now contradicts the new registry fallback rule.

Line 344 states "Environment variables take priority over bunfig.toml," but the newly added carve-out says NPM_CONFIG_REGISTRY/npm_config_registry apply only when no registry is configured — i.e., these specific env vars do not take priority over bunfig.toml. Consider qualifying the blanket statement (e.g., "...except NPM_CONFIG_REGISTRY/npm_config_registry, see below") to avoid misleading readers.

📝 Suggested wording tweak
-Environment variables take priority over `bunfig.toml`.
+Environment variables take priority over `bunfig.toml`, with the exception of `NPM_CONFIG_REGISTRY`/`npm_config_registry` (see below).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/pm/cli/install.mdx` around lines 344 - 356, Qualify the introductory
“Environment variables take priority over bunfig.toml” statement to exclude
NPM_CONFIG_REGISTRY and npm_config_registry, which only act as fallbacks when no
registry is configured. Keep the existing registry precedence explanation below
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@docs/pm/cli/install.mdx`:
- Around line 344-356: Qualify the introductory “Environment variables take
priority over bunfig.toml” statement to exclude NPM_CONFIG_REGISTRY and
npm_config_registry, which only act as fallbacks when no registry is configured.
Keep the existing registry precedence explanation below unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9f3ff2fe-0782-492c-9125-808a7558337a

📥 Commits

Reviewing files that changed from the base of the PR and between cc0c1e8 and 26c0776.

📒 Files selected for processing (3)
  • docs/pm/cli/install.mdx
  • src/install/PackageManager/PackageManagerOptions.rs
  • test/cli/install/bun-install-registry.test.ts

@robobun

robobun commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator Author

Good catch on the docs contradiction: the blanket "Environment variables take priority over bunfig.toml" line predated the fallback carve-out. Reworded it in 05d5924 to "These environment variables take priority over bunfig.toml", scoping it to the BUN_CONFIG_* table above the npm-compat fallback note.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/pm/cli/install.mdx (1)

355-356: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clarify that an empty registry is treated as unset.

Options::load() only considers a registry configured when its URL is non-empty, so registry = "" still allows NPM_CONFIG_REGISTRY/npm_config_registry fallback. Change “no registry is explicitly configured” to “no non-empty registry is configured” to match the implementation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/pm/cli/install.mdx` around lines 355 - 356, Update the registry fallback
documentation in the npm compatibility section to say it applies only when no
non-empty registry is configured in bunfig.toml or .npmrc. Preserve the stated
override precedence for BUN_CONFIG_REGISTRY and --registry.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@docs/pm/cli/install.mdx`:
- Around line 355-356: Update the registry fallback documentation in the npm
compatibility section to say it applies only when no non-empty registry is
configured in bunfig.toml or .npmrc. Preserve the stated override precedence for
BUN_CONFIG_REGISTRY and --registry.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 74d1a1b7-f307-4a22-983c-3bb548efba9d

📥 Commits

Reviewing files that changed from the base of the PR and between 26c0776 and 05d5924.

📒 Files selected for processing (1)
  • docs/pm/cli/install.mdx

@robobun

robobun commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator Author

Leaving the docs wording as is: "explicitly configured" describes intended usage, and an empty registry = "" in bunfig.toml is a degenerate value rather than a configuration someone writes on purpose. Treating it as unset (so the env fallback applies) is the sensible behavior, and qualifying the user docs with "non-empty" would add noise for an edge case nobody hits.

Comment thread src/install/PackageManager/PackageManagerOptions.rs
An .npmrc containing only an auth line for the default registry host
(what npm login writes) backfilled default_registry.url with the
default URL, which made the new explicit-registry check treat it as a
configured registry and drop the npm_config_registry fallback. Leave
the url empty on that path, matching how bunfig represents auth-only
registry config, and let Options::load fill in the default.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix in 3d91bfe addresses my earlier concern — the .npmrc auth-only synthesis now leaves url empty, the host-comparison in load_npmrc falls back to DEFAULT_URL when empty, and I confirmed Options::load and the ini_jsc test API are the only other consumers of default_registry.url (both handle empty). Deferring to a maintainer to sign off on the precedence model itself, since registry selection controls where packages are fetched from and where credentials are sent.

Extended reasoning...

Overview

Changes registry-selection precedence in bun install so an explicit registry in bunfig.toml/.npmrc wins over NPM_CONFIG_REGISTRY/npm_config_registry, while BUN_CONFIG_REGISTRY and --registry still override config files. Touches PackageManagerOptions.rs (env-key selection), src/ini/lib.rs (auth-only .npmrc now leaves url empty instead of backfilling DEFAULT_URL), docs, and adds three end-to-end tests plus updates four loadNpmrc unit assertions.

Follow-up on prior review

My earlier finding (auth-only ~/.npmrc from npm login would defeat the !url.is_empty() guard) was fixed by changing the .npmrc parser to match bunfig's empty-url representation for auth-only config. I re-audited consumers of default_registry.url: Options::load already fills empty with DEFAULT_URL, load_npmrc's host/pathname derivation now guards on is_empty() and falls back to DEFAULT_URL, and ini_jsc.rs is test-only. The multi-.npmrc token-merge path is preserved because the second load_npmrc call sees url.is_empty() and uses the default host for matching. The token-carry logic in the env-var override path (prev_url.host == new_url.host) correctly drops the npmjs.org token when redirecting to a different mirror host, which the new test asserts.

Security risks

Registry selection is security-adjacent: it determines which server receives package requests and which credentials are attached. The change narrows when an env var can silently redirect traffic (good), and the token-host check already prevents cross-host token leakage. No new credential-forwarding path is introduced.

Level of scrutiny

This is a deliberate behavioral/design change to config precedence rather than a mechanical fix. The ordering (--registry > BUN_CONFIG_REGISTRY > config files > npm_config_* > default) is reasonable and documented, but it's the kind of user-facing contract a maintainer should confirm — particularly the asymmetry between BUN_CONFIG_REGISTRY (still overrides) and npm_config_registry (now fallback), and the .npmrc representation change.

Other factors

Three new e2e tests cover both directions (bunfig wins; env var still applies with no config; auth-only .npmrc doesn't count as configured). CI build #72974 was still running at review time.

dylan-conway pushed a commit that referenced this pull request Jul 24, 2026
…35327)

### What does this PR do?

The registry/token env-var scan loops in `Options::load`
(`src/install/PackageManager/PackageManagerOptions.rs`) carried a
`did_set` flag with an `if !did_set` guard in place of `break`. This was
a workaround for a Zig stage1 compiler bug where `break` inside `inline
for` was broken, ported verbatim into the Rust rewrite along with its
explanatory comment:

```rust
self.scope.token = registry_.into();
did_set = true;
// stage1 bug: break inside inline is broken
// break :load_registry;
```

The Zig sources were removed in #32621 and the stage1 compiler no longer
exists. In Rust this is just a plain `for` loop, so use `break` directly
and drop:

- the `did_set` flag and `if !did_set` wrapper (both loops)
- the dead `// break :load_registry;` Zig-syntax comment
- the `// load_registry:` label comment
- the two `// was \`inline for\`; homogeneous elements -> plain for.`
porting notes

### Behavior

**No observable change.** The `if !did_set` guard already ensured the
first matching env var wins; this PR just expresses that with `break`.
Verified empirically against the released binary:

```
BUN_CONFIG_TOKEN=a NPM_CONFIG_TOKEN=b npm_config_token=c bun install
  -> Authorization: Bearer a
```

### Tests

Added to `test/cli/install/bun-install-registry.test.ts` to lock in the
priority order (previously untested):

- `BUN_CONFIG_TOKEN` wins over `NPM_CONFIG_TOKEN` and `npm_config_token`
- empty `BUN_CONFIG_TOKEN` falls through to `NPM_CONFIG_TOKEN`
- `BUN_CONFIG_REGISTRY` wins over `NPM_CONFIG_REGISTRY` /
`npm_config_registry`

These pass on the released binary as well; they exist to pin the
refactor and guard against future changes to the key ordering.

Related: #34170 touches the same block for a different concern (bunfig
vs. env-var precedence); whichever lands second will need a small
rebase.

<!-- robobun:evidence:begin -->

---

**no test proof** · iteration 0 · Platform-specific test(s) that do not
run on this machine. Deferring to CI, which covers all platforms:
test/cli/install/bun-install-registry.test.ts

<!-- robobun:evidence:end -->

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
@robobun

robobun commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator Author

Closing as part of a cleanup of stale pull requests. This PR has had no new commits since 2026-07-14, it conflicts with main, and its last CI run failed. This is not a judgment on the fix itself. The linked issue (#34168) stays open. If the problem still reproduces on a current build, reopen this PR after a rebase or open a new one against main.

@robobun robobun closed this Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bunfig.toml registry setting ignored when npm_config_registry env var is set

1 participant