3.1.8 Registry Structure & Custom Registries

extra

An index registry is the metadata store Bazel consults during module resolution. The Bazel Central Registry is just the public instance of that format. A private or forked registry uses the same layout, so once you understand the files Bazel reads and how --registry chooses among them, you understand both public and internal module hosting.1,2 If 3.1.1 Bzlmod (MODULE.bazel) explained that Bazel resolves modules through registries, this article is the file-format view of that statement.

An index registry is a small filesystem tree

Bazel only supports index registries: either a local directory or a static HTTP server with a fixed layout.1 At the top level you may have an optional bazel_registry.json, then a modules/ directory, and under that one directory per module.1 The registry-wide file is where shared archive mirrors and module_base_path for local_path entries live.1

my-registry/
  bazel_registry.json
  modules/
    rules_foo/
      metadata.json
      1.2.3/
        MODULE.bazel
        source.json
        patches/
        overlay/
        presubmit.yml   # BCR only

Two details are easy to miss. metadata.json is per module, not per version, and it mainly lists available versions plus optional yanked-version metadata.1 The version directory then contains the registry-owned MODULE.bazel used during resolution and the source.json that tells Bazel how to fetch the actual source tree.1,2

The registry copy of MODULE.bazel is the important one

During Bzlmod resolution, Bazel asks the registry for dependency MODULE.bazel files first, resolves the graph, and only then consults the registry again to learn how to define the backing repositories.2 That is why the MODULE.bazel inside a registry entry is not just a mirror of whatever happens to be in the source archive.1,2

For released modules, the safest pattern is to treat the registry copy as the source of truth for the release version and keep the source archive MODULE.bazel free of version hard-coding when possible.1,3 That avoids awkward behavior when users switch to non-registry overrides during local development, because the source tree may no longer represent the published release exactly.3

source.json chooses how Bazel gets the source

source.json is required for each published version, and its schema depends on the source type.1 The default archive type points at a versioned archive URL and can also carry mirror_urls, integrity, strip_prefix, plus optional overlay/ and patches/ directories that Bazel applies when materializing the repo.1 git_repository entries forward the expected Git attributes such as remote, commit, or tag, and can also carry patch metadata (patches plus patch_strip) for registry-owned changes to the cloned checkout. local_path entries symlink to a local checkout instead of downloading anything.1

The subtle part is local_path: if the path is relative, Bazel resolves it through module_base_path from bazel_registry.json, and a relative-on-relative setup only works when the registry itself is local and used via file://....1 That makes local_path useful for private, locally hosted registries, but not something you can publish to a generic static HTTP host and expect every consumer to use unchanged.1

BCR adds policy on top of the base format

The BCR is an index registry backed by the bazelbuild/bazel-central-registry repository and browsed through registry.bazel.build.1 What makes it special is not a different protocol, but extra policy. In addition to the normal registry layout, each published version needs a presubmit.yml file so BCR CI can run interoperability checks across platforms and dependency combinations.1

That distinction matters because a custom registry can be much smaller. If your company needs to host proprietary modules or a curated fork, you do not need a second dependency mechanism. You need the same index-registry shape and stable source metadata.1

You can inspect that split in the live BCR repository: a module directory such as modules/rules_cc/ keeps module-wide metadata beside immutable version directories, while docs/README.md documents the BCR-only validation and presubmit.yml layer.4 Treat the live tree as a concrete format example. The base registry contract remains the Bazel registry specification.

--registry is how you build a registry chain

The repeatable --registry flag controls where Bazel looks for modules.1 Earlier entries take precedence, which lets you put an internal registry or fork ahead of the public BCR.1 The easy-to-miss behavior is that once you start passing --registry, Bazel stops using the default BCR automatically, so you must add https://bcr.bazel.build back explicitly if you still want it as a fallback.1

common --registry=https://raw.githubusercontent.com/my-org/bazel-central-registry/main/
common --registry=https://bcr.bazel.build

If the registry is a GitHub fork, the URL has to point at the raw content host, not the normal repository web UI.1 If the registry is local, a directory on disk is enough, which is why local BCR clones are one practical building block for restricted-network setups alongside the broader strategies in 3.1.9 Offline / Air-Gapped Builds.1,5 The local-registry-chain snippet keeps that shape runnable: a root module depends on the local-only registry_dep@1.0.0, the registry-side MODULE.bazel supplies the published version, and the assertion script runs with the local registry first and BCR explicitly configured as fallback.

Start with overrides, then promote to a registry

Before publishing, get the dependency working with overrides. 3.1.7 Registry Immutability explains why the registry must not become the iteration surface. The registry-layout concern begins when that working dependency is promoted into the index and placed in an explicit --registry chain.3,6 See 3.1.6 BCR Infrastructure for download reliability and failover policy.

key takeaway

BCR and private registries use the same index format. The registry-owned MODULE.bazel declares resolution metadata, source.json describes source materialization, and repeated --registry flags form an explicit precedence chain. Continue to 3.1.7 Registry Immutability for publication immutability and 3.1.6 BCR Infrastructure for availability and mirrors.1

extra

Publishing to BCR Is the Next Layer

Publishing adds repository-maintainer concerns on top of the raw registry format: versioned and stable release archives, a small test module or representative tests, and BCR-specific presubmit.yml checks.1,7 Tooling can automate a lot of this, including the registry-side patching needed to stamp a release version into the fetched module tree, but that release automation belongs with ruleset maintenance in 4.11 Ruleset Packaging & Publishing rather than the core registry-format discussion here.3,7

Check your understanding · 3 questions

1.When you add a second --registry flag, Bazel no longer falls back to the Bazel Central Registry automatically. Why?

Select one answer

2.Match each registry file to its role:

Drag each answer onto the matching prompt, or click an answer and then click a prompt

Answers
bazel_registry.json
metadata.json
source.json
MODULE.bazel (in registry)

3.True or false about the local_path source type in source.json:

Choose True or False for each sentence

A local_path entry works correctly when the registry is hosted on a generic static HTTP server.
If the path in a local_path entry is relative, Bazel resolves it through module_base_path from bazel_registry.json.
0 of 3 answered

Footnotes

  1. Bazel registries — index registry layout, bazel_registry.json, metadata.json, source.json source types including archive, git_repository patch metadata, and local_path, BCR-specific presubmit.yml, and --registry precedence 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

  2. Bazel modules — resolution flow: Bazel reads registry MODULE.bazel files first, then consults registries again to define backing repos 1 2 3 4

  3. Frequently asked questions — why version metadata should live in the registry-side module entry and how publish automation patches source archives 1 2 3 4

  4. Bazel Central Registry repository mapmodules/rules_cc/ shows the live module/version layout, while docs/README.md explains BCR validation and presubmit policy.

  5. Build programs with Bazel — using a local BCR clone with --registry in restricted-network builds

  6. A Product-First Approach to Growing BCR - Jordan Mele, Canva — overrides-first workflow, in-repo registry pitfalls, and practical BCR maintenance lessons

  7. Bzlmod Migration Guide — stable release archives, test modules, and publish-to-BCR guidance 1 2