3.1.7 Registry Immutability

recommended

Bazel registries can be local directories or static HTTP servers, so pointing --registry at a repo-owned directory looks tempting at first.1 The catch is that Bazel treats registry metadata like published input, not like a live scratchpad: the registry copy of MODULE.bazel participates in external dependency resolution, and the Bazel server caches registry files in memory with the expectation that they do not change after publication.1,2,3 That assumption is harmless for append-only registries such as the BCR, but it becomes a real maintainer trap if you keep editing a local or in-repo registry after Bazel has already read it.3,4

Why registry edits are different from source edits

An index registry does more than point at source archives. It also carries the registry-side MODULE.bazel, source.json, and optional patches and overlays that Bazel uses while resolving and fetching a module version.1 The MODULE.bazel stored in the registry is the source of truth during external dependency resolution, not the MODULE.bazel sitting inside the source archive.2

That is why a registry entry behaves more like published package metadata than like a checkout you can safely tweak in place. If you need to experiment on a dependency, the normal workflow from 3.1.1 Bzlmod (MODULE.bazel) is to use an override, not to mutate an already-consumed registry version.5

The warm-server failure mode

The operational gotcha shows up as soon as the same Bazel server sees both the old and new registry contents. Even a file:/// registry clone may require bazel shutdown before every command while you iterate, because the Bazel server caches registry fetches in memory.3

That same behavior becomes much more painful in CI. In a large monorepo with workers that keep Bazel warm between jobs, an in-repo registry exposes it: a defective registry change may not be detected immediately because Bazel keeps reusing cached registry metadata, and recovery requires more than reverting the bad commit — the published version also has to change and the merge queue has to be reset.4 This is a different failure mode from mirror availability and downloader setup in 3.1.6 BCR Infrastructure. The bytes can be local and reachable, but Bazel is still intentionally trusting the previously fetched registry metadata.

common --registry=file://%workspace%/third_party/registry

That configuration is supported.1,4 It is just unsafe if the directory is treated like normal source code that contributors keep editing after Bazel has cached it.

Safer maintainer workflow

For local development, use a non-registry override first. local_path_override is the simplest option when you have a checkout on disk, and Bazel also supports archive- and Git-based non-registry overrides for other cases.5 Those overrides remove the module from registry-based version resolution, which is exactly what you want while the dependency is still moving.5

Once the dependency works, publish a new immutable registry version or contribute the change to BCR. If your organization really needs a private registry, treat it as append-only published metadata and use 3.1.8 Registry Structure & Custom Registries for the hosting mechanics. Do not use the registry itself as the iteration surface. That is what overrides are for.4,5

key takeaway

A registry is not a live development workspace. Bazel assumes registry files are immutable for the life of the server, so mutating an existing entry is asking for stale metadata bugs. Iterate with overrides, then publish a new registry version once the dependency is ready.3,4,5

Check your understanding · 3 questions

1.A team keeps a local in-repo registry and edits it directly after publishing a version. What failure mode should they expect?

Select one answer

2.True or false about registry immutability:

Choose True or False for each sentence

Using a file:/// URL for a local registry makes it safe to edit registry entries during development because Bazel always re-reads local files.
The correct workflow for iterating on a dependency is to use an override (e.g., local_path_override), then publish a new registry version once stable.

3.Why does the registry copy of MODULE.bazel take precedence over the one inside the source archive during dependency resolution?

Select one answer

0 of 3 answered

Footnotes

  1. Bazel registries — local-directory and static-HTTP registries, plus the registry-side MODULE.bazel, source.json, patches, and overlays 1 2 3 4

  2. Frequently asked questions — the registry MODULE.bazel is the source of truth for module version during external dependency resolution 1 2

  3. Adopting Bazel's new package manager — local registry clones are cached by the Bazel server, so testing registry edits often requires bazel shutdown 1 2 3 4

  4. A Product-First Approach to Growing BCR - Jordan Mele, Canva — immutability requirement, in-memory registry cache, in-repo registry failure mode, and override-first recommendation 1 2 3 4 5

  5. Bazel modules — non-registry overrides such as local_path_override, archive_override, and git_override 1 2 3 4 5