Setting Up Bazel Remote Caching with bazel-remote: A Practical Guide
Learn how to set up Bazel remote caching with bazel-remote, configure .bazelrc for team‑wide sharing, verify hits, and avoid cache‑poisoning risks.
07 May 2026, 14:10 UTC

Why rebuild what’s already built?
In a team of developers and CI pipelines, the same source files are often compiled many times a day. Each rebuild wastes CPU cycles and delays feedback. Bazel’s remote caching lets a machine download previously built action outputs from a shared server when the inputs match, turning redundant work into a simple network fetch.
How Bazel decides if an action can be cached
Before executing an action, Bazel hashes all of its declared inputs—source files, toolchain version, command‑line flags, and any environment variables listed as inputs—into an action key. If that key already exists in the remote cache, Bazel skips local execution and downloads the stored output. The guarantee of identical output holds only for hermetic actions; non‑hermetic reads (e.g., system files, timestamps) are not part of the key and can cause cache poisoning.
Deploying a simple cache server with bazel-remote
For a low‑risk first step, run the open‑source bazel-remote HTTP cache on a team VM. The example below assumes Bazel 6.0 or newer, where the caching flags are stable.
# On the cache VM (run once)
bazel-remote --dir=/var/bazel-cache --port=8080
Make the cache reachable at http://cache.internal.example.com:8080.
Team‑wide configuration via .bazelrc
Add the following lines to the repository’s .bazelrc (checked into version control) so every developer and CI job uses the same settings.
# Point to the remote cache server
build --remote_cache=http://cache.internal.example.com:8080
# Upload local build results to the cache (default: true)
# To disable uploads, use --noremote_upload_local_results
build --remote_upload_local_results=true
# Enable compression to reduce bandwidth (stable in Bazel 6+)
build --remote_cache_compression
# Download only top‑level outputs; intermediate cache hits are skipped
build --remote_download_outputs=toplevel
Explanation:
--remote_cachetells Bazel where to store/retrieve action outputs.--remote_upload_local_resultscontrols whether a local build populates the cache. The flag defaults totrue; explicitly setting it clarifies intent, and the inverse flag disables uploads.--remote_cache_compressionenables gzip compression of cached artifacts (available as a stable flag from Bazel 6.0).--remote_download_outputs=toplevelreduces download size by fetching only the final requested artifacts, not intermediate outputs that may already be cached locally.
Verifying that the cache works
After configuring .bazelrc, run a build, clean the local state, and rebuild:
# First build – populates the cache
bazel build //path/to:target
# Clear local action cache
bazel clean
# Rebuild – look for cache hits in the console output
bazel build //path/to:target
Successful remote caching appears as lines like:
INFO: 7 processes: 3 remote cache hit, 4 local.
Alternatively, inspect the build events with bazel build ... --build_event_text_file=events.txt and search for "remote cache hit".
Trade‑off: cache poisoning from non‑hermetic actions
If an action reads an undeclared system file or uses a clock value, its action key will not reflect that variability. Two developers with different system states could upload different outputs under the same key, poisoning the cache. The safest approach is to audit rules for hermeticity before enabling --remote_upload_local_results. A quick check is to build the same target on two machines with identical Bazel versions and compare the action keys via bazel aquery --output=proto //path/to:target; differing keys indicate a hermeticity problem.
Infrastructure and security considerations
| Aspect | Detail | Mitigation |
|---|---|---|
| Storage growth | Monorepos can generate many gigabytes per day. | Configure bazel-remote with a size limit (e.g., --max_size=50GB) which triggers LRU eviction when exceeded. |
| Security | An unauthenticated HTTP cache allows anyone to inject binaries. | Terminate TLS at a reverse proxy (NGINX, Envoy) and optionally use Bazel’s credential helper (--remote_http_credential) or mTLS. |
| Bandwidth vs. local build | Downloading large binaries may be slower than a local compile on a fast machine. | Use --remote_download_outputs=toplevel to fetch only what you need, and monitor hit ratios to adjust cache size. |
Actionable next steps
- Deploy a
bazel-remoteinstance with a size limit and TLS termination. - Add the .bazelrc snippet above, committing it to the repo.
- Run a few representative builds and verify remote cache hit messages appear.
- Audit critical rules for hermeticity (e.g., using
bazel query --output=graphto spot undeclared file reads) before enabling uploads from developer workstations. - Monitor cache hit ratio and storage usage; adjust the
--max_sizeflag or retention policy as needed.
Remote caching is a low‑effort way to cut duplicate work while you evaluate whether a full remote execution fleet is needed for your organization.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.