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:

Schematic Example of Bazel Cache Miss
//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 blobs

Later 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.

Schematic Example of Bazel Cache Hit
//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 sooner

BuildFetch 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:

Schematic Example of Cold Build
$ 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 4s

Subsequent build, whether by an engineer, AI agent, or fresh CI agent, can finish in seconds:

Schematic Example of Warm Build
$ 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 4s

Configure 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 as reapi protocol family, bazel client, and your Project tenant
  • --remote_cache_header='Authorization=Bearer <TOKEN>' — pass the generated Token
.bazelrc
# 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=false

Use a cache:readonly Token. Normal Bazel commands read from the remote cache without uploading local results:

Bash
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:

.bazelrc
build:ci --remote_upload_local_results=true
Bash
export 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}"

See Also