Configure Bazel Remote Cache
Last updated: September 21, 2026
What is Bazel Remote Cache
A Bazel remote cache saves significant build time by reusing action outputs from previous builds when an action's inputs have not changed. Bazel can use a Remote Cache shared across engineer workstations, CI, and AI agent environments.
Bazel breaks a build into a graph of discrete actions. Each action has declared inputs, a list of output filenames, environment variables, etc. Bazel computes stable hash from inputs of each action to use as a key and looks keys up in the Remote Cache before running the expensive work locally.
The Remote Cache stores an Action Cache (AC) for build action metadata and a Content-Addressable Store (CAS) for actual output files. One Bazel AC entry can reference many CAS entries. On a cache miss Bazel runs the action (slow) and stores the AC entry plus related CAS blobs; on a cache hit Bazel restores outputs (quick) and reports the step as a remote cache hit.
BuildFetch Cache implements native support of both Bazel Remote Cache protocols:
- gRPC Remote Cache API (REAPI ActionCache, ContentAddressableStorage, Capabilities, ByteStream, etc) — recommended for best performance; this is what the configuration examples below use.
- HTTP Remote Cache API — fully supported on the HTTPS project cache URL.
Bazel selects the transport from the --remote_cache URL scheme (grpcs / grpc or https / http).
For Bazel Remote Execution, BuildFetch Cache can be paired with Buildbarn Remote Execution: Buildbarn executes actions while BuildFetch serves the shared REAPI Action Cache and CAS for Bazel and Buildbarn workers.
Importantly: like Gradle and Sbt, Bazel also caches Test runs, this allows teams to save significant CI time and cost.
Schematic example: say a first run of //libs/dto:protobuf misses the cache, spends about few minutes generating sources from ProtoBuf, and stores the Action Cache entry plus CAS blobs:
//libs/dto:protobuf
Inputs
+----------------------+
| .proto files |
| declared deps |
| command line |
| env vars |
| ... |
+----------+-----------+
|
v
Compute action digests
|
v
+----------------------+
| Bazel Remote Cache |
| AC key: a3f9...c2 |
| status: MISS |
+----------+-----------+
|
v
Run action (few minutes)
|
v
Outputs: generated sources, jars, ...
|
v
Store AC entry + CAS blobsLater builds with the same inputs reuse that entry. Bazel computes the same digests, hits the Action Cache, and quickly restores outputs. With Build without the Bytes (default since Bazel 7), Bazel can often resolve AC entries without downloading most of the heavier CAS blobs that weren't necessary for the end build target.
//libs/dto:protobuf (same inputs)
Inputs unchanged
.proto files · deps · command line · env
|
v
Same action digests
|
v
+----------------------+
| Bazel Remote Cache |
| AC key: a3f9...c2 |
| status: HIT |
+----------+-----------+
|
v
Restore outputs
(or skip most CAS with BwoB)
|
v
Skip ~15s action
Report remote cache hit
Build graph continues soonerBuildFetch Cache is specifically optimized to serve AC and CAS quickly through its NVMe -> SSD tiered storage system. It also correctly preserves Bazel AC -> CAS relations when it evicts entries via LRU GC, which avoids the common failure mode where a remote cache hits an AC entry but then misses related CAS entries.
Share Bazel Remote Cache Between Machines
Remote Bazel Cache
For Bazel action outputs to be shared across machines, a remote cache must be configured. Local disk cache only helps on a single machine.
A remote Bazel cache lets teams share action outputs across engineer workstations, CI, and AI agent environments.
CI, having a more reproducible and controlled environment, typically both reads from and writes to the shared remote cache. Engineers and AI agents read those outputs without uploading new entries (for example via --remote_upload_local_results=false).
That keeps the cache warm from reproducible CI builds while reducing repeated work on other machines. Bazel reuses an output only when action inputs match, so keep builds hermetic and reproducible when sharing a cache.
Instead of recompiling, retesting, and repackaging on every machine, Bazel retrieves cached action outputs and reports them as remote cache hit — turning builds that took minutes into cached builds that finish in seconds.
Cached Bazel Build Example
After CI populates the Remote Cache, a clean build on another machine can resolve every expensive action from cache. In a typical scenario:
First build, where CI populates the remote cache:
$ bazel build //... --config=ci
INFO: Analyzed 45 targets (12 packages loaded, 234 targets configured).
INFO: Found 45 targets...
INFO: 45 processes: 45 internal.
INFO: Build completed successfully, 45 total actions in 10m 4sSubsequent build, whether by an engineer, AI agent, or fresh CI agent, can finish in seconds:
$ bazel build //...
INFO: Analyzed 45 targets (0 packages loaded, 0 targets configured).
INFO: Found 45 targets...
[1/45] //dto:protobuf - cache hit
[2/45] //auth:lib - cache hit
[3/45] //api:lib - cache hit
...
INFO: 45 processes: 2 internal, 43 remote cache hit.
INFO: Build completed successfully, 45 total actions in 4sConfigure Bazel Remote Cache
Before setting up remote cache, ensure you have created BuildFetch Project and Token(s).
Official Bazel Remote Caching documentation: https://bazel.build/remote/caching.
BuildFetch supports both the gRPC and HTTP remote cache APIs. The examples below configure the gRPC Remote Cache API (recommended). Keep flags in .bazelrc and use named configuration groups to separate CI read-write access from engineer read-only access.
BuildFetch also supports Bazel’s HTTP remote cache protocol on the HTTPS project cache URL. This page documents the gRPC setup only.
Cache Access
Use a cache:readonly Token by default on developer and AI agent machines. Trusted environments like CI should use a cache:readwrite Token and explicitly enable uploads.
For Token management, rotation, and Open Source guidance, see Set up BuildFetch Cache Project.
Read-only
Generate a local .bazelrc.local file from the Project Cache Setup tab. Take the HTTPS project cache host (for example cache.region.buildfetch.com from https://cache.region.buildfetch.com/<PROJECT_ID>/bazel) and configure:
--remote_cache=grpcs://<CACHE_HOST>— gRPC over TLS to the same public cache host--remote_instance_name=reapi/bazel/<PROJECT_ID>— namespaced asreapiprotocol family,bazelclient, and your Project tenant--remote_cache_header='Authorization=Bearer <TOKEN>'— pass the generated Token
# gRPC Remote Cache (recommended)
build --remote_cache=grpcs://<CACHE_HOST>
build --remote_instance_name=reapi/bazel/<PROJECT_ID>
build --remote_timeout=30
build --remote_cache_header='Authorization=Bearer <TOKEN>'
build --remote_upload_local_results=falseUse a cache:readonly Token. Normal Bazel commands read from the remote cache without uploading local results:
export BUILDFETCH_BAZEL_REMOTE_CACHE_HOST="cache.region.buildfetch.com"
export BUILDFETCH_BAZEL_PROJECT_ID="project-id"
export BUILDFETCH_BAZEL_REMOTE_CACHE_TOKEN="..."
bazel test //... \
--remote_cache="grpcs://${BUILDFETCH_BAZEL_REMOTE_CACHE_HOST}" \
--remote_instance_name="reapi/bazel/${BUILDFETCH_BAZEL_PROJECT_ID}" \
--remote_cache_header="Authorization=Bearer ${BUILDFETCH_BAZEL_REMOTE_CACHE_TOKEN}"Read-write
Enable remote uploads with the ci config:
build:ci --remote_upload_local_results=trueexport BUILDFETCH_BAZEL_REMOTE_CACHE_HOST="cache.region.buildfetch.com"
export BUILDFETCH_BAZEL_PROJECT_ID="project-id"
export BUILDFETCH_BAZEL_REMOTE_CACHE_TOKEN="..."
bazel build //... --config=ci \
--remote_cache="grpcs://${BUILDFETCH_BAZEL_REMOTE_CACHE_HOST}" \
--remote_instance_name="reapi/bazel/${BUILDFETCH_BAZEL_PROJECT_ID}" \
--remote_cache_header="Authorization=Bearer ${BUILDFETCH_BAZEL_REMOTE_CACHE_TOKEN}"