3.1.9 Offline / Air-Gapped Builds
extraOffline builds are not one Bazel feature. Bazel gives you two local strategies with different trade-offs: keep downloaded artifacts in a shared repository cache, or vendor external repositories into a workspace-controlled directory. The repository cache preserves Bazel's normal fetch flow and just removes repeated downloads. Vendor mode makes the dependency sources travel with the repo and can work on another machine with no prewarmed cache at all.1,2,3
Repository cache keeps normal dependency resolution
1.1.11 bazel fetch introduced prefetching. The maintainer step is to make the cache location explicit and treat it as reusable machine state:
bazel fetch --repository_cache=/srv/bazel-repo-cache //...
bazel build --nofetch --repository_cache=/srv/bazel-repo-cache //...
The repository cache stores downloaded files for external repositories once per machine. Bazel shares that directory across workspaces and installed Bazel versions, and it only reuses an entry when the download request has a matching SHA256. That is why hashes are not just a security nicety. They are also what makes cache reuse trustworthy.2 The cache is separate from the workspace-local state discussed in 1.1.6 bazel clean, and the broader cache taxonomy is in 2.4.2 Where Bazel Caches Things.2,4
The boundary matters. A warm repository cache does not mean a workspace already has extracted repositories or build outputs. Bazel may still materialize repos under output_base/external for the current workspace. The cache only removes the network download step.1,2,4 It is also never cleaned automatically, which is convenient for offline prep but something maintainers have to manage intentionally.2,4
Vendor mode makes the workspace carry the dependencies
Use bazel vendor when "available on this machine" is not enough. Vendor mode copies external repositories into a directory selected by --vendor_dir, so later builds reuse that local copy instead of refetching it.1
bazel vendor --vendor_dir=vendor_src //app:server
bazel build --vendor_dir=vendor_src //app:server
You can vendor one repo with --repo, the dependencies of specific target patterns, or the whole resolved graph. Unlike a repository cache, vendored sources can be checked in, transferred to another machine, and built without network access or a pre-existing repository cache.1 Bazel also vendors registry files under <vendor_dir>/_registries, which is why module resolution can stay offline too.1
The vendor-mode snippet makes the generated layout inspectable without relying on a public dependency: its assertion script creates a local source archive, vendors it into vendor_src, removes the original archive, then verifies a build with a new output base and empty repository cache. Its small local registry remains available for module resolution, so this check specifically proves that the dependency source comes from the vendor directory rather than warm Bazel state. It is not presented as a network-blocking test for every implicit Bazel tool repository.
Vendoring is not fire-and-forget. If the target set, external dependency graph, build configuration, or Bazel version changes, you may need to re-vendor so the offline build still matches reality.1
One easy trap is assuming bazel vendor //... covers every future Bazel subcommand. It vendors dependencies reachable from the requested targets, but some subcommands have implicit tool dependencies outside that target graph. If your offline workflow needs commands such as bazel mod tidy, include Bazel's subcommand tools filegroup in the vendor invocation:1
bazel vendor //... @bazel_tools//tools:tools_for_bazel_subcommands
Without that extra target, a build may work offline while a maintenance command still tries to fetch a tool.
VENDOR.bazel controls what stays fixed
Inside the vendor directory, VENDOR.bazel lets you tell Bazel which repos it should stop touching. Its directives take canonical repo names rather than the everyday apparent @name labels, which is the same naming split described in 3.1.3 Repo Mapping.1,5
ignore("@@rules_cc+")
pin("@@bazel_skylib+")
ignore() excludes a repository from vendor mode entirely. pin() freezes the current vendored copy and makes Bazel use it as if an --override_repository were in effect, which is the right move before you edit the vendored source by hand.1,5 Under the hood Bazel still projects those repos back into the normal output_base/external layout, so label syntax does not change just because the source now lives under your vendor directory.1
Choose the lighter tactic first
Use the repository cache when you want Bazel's normal dependency mechanisms to keep working, but you want repeatable local/offline fetch behavior on managed developer machines or CI workers. Use vendoring when the repository itself must carry the dependency bytes, or when you need to patch and review external code locally.1,2,3
Once you need internal mirrors, local registry copies, URL rewriting, or CI jobs that deliberately block public Internet access, you have crossed from local offline prep into infrastructure design. Continue with 3.1.6 BCR Infrastructure and 3.1.8 Registry Structure & Custom Registries for dependency infrastructure, then 6.5 Bazel CI at Scale and 6.7.2 Operating Bazel Builds in Air-Gapped Environments for the broader CI and air-gapped operating models.2,3,6
For the registry-copy side of that boundary, the local-registry-chain snippet shows the smallest local index-registry entry that resolves its demo module while keeping BCR explicitly configured as fallback for other modules.
--repository_cache and bazel vendor solve different problems. The repository cache is a shared machine-level download cache: light, fast, and good when you control the environment. Vendor mode is workspace-level and portable: heavier, but it lets the repo carry its own external sources and even local registry files. Start with the cache. Move to vendoring when the bytes need to travel with the checkout.
Check your understanding · 3 questions
1.A team wants to build on a machine with no network access. They already have a warm repository cache on that machine. Which statement is accurate?
Select one answer
2.Match each offline strategy to its defining characteristic:
Drag each answer onto the matching prompt, or click an answer and then click a prompt
3.True or false about vendor mode:
Choose True or False for each sentence
bazel vendor //... automatically vendors the implicit tools needed by Bazel subcommands such as bazel mod tidy.Footnotes
-
Vendor Mode —
--vendor_dir,bazel vendormodes, vendoring@bazel_tools//tools:tools_for_bazel_subcommandsfor offline Bazel subcommands,VENDOR.bazel, vendored registry files, and symlink behavior ↩1 ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 -
Build programs with Bazel —
bazel fetch, repository cache semantics,--repository_cache, and air-gapped machine preparation ↩1 ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 -
Frequently asked questions —
--nofetch, offline-build preparation,bazel vendorvsbazel fetch, and insulating builds from the Internet ↩1 ↩2 ↩3 -
The Many Caches of Bazel — repository cache stores archives only, is shared across workspaces, and is not pruned automatically ↩1 ↩2 ↩3
-
VENDOR.bazel files —
ignore()andpin()API surface ↩1 ↩2 -
How we build without the public internet — blocked-Internet verification jobs, internal mirrors, and downloader-config rewrites as the next layer beyond local offline tactics ↩