3.6.5 Simple Remote Cache Setup
recommended--disk_cache is the cheapest way to keep CI from repeating work, but it only helps the machine that owns that directory. Once builds run on multiple runners, or you want developer laptops and CI to reuse the same outputs, the cache has to live behind a network endpoint. Bazel's remote cache lets one machine upload action results and another machine download them instead of re-executing the same action.1,2 That makes it the natural next step after 3.6.4 Disk Cache in CI.
When a Disk Cache Stops Being Enough
On a single persistent runner, --disk_cache is usually the right first move. The moment CI becomes stateless or horizontally scaled, local cache files stop being shareable: when the runner disappears, the cache disappears with it. For stateless workers, a remote cache is the recommended step once multiple workers need the same outputs.3 The same transition looks like this from another angle: a shared remote cache can be reused across branches, workspaces, developer machines, and CI build drones, which separates short-lived compute from persistent storage.4
If builds stay on one persistent runner, use 3.6.4 Disk Cache in CI. Move the cache to the network when stateless or multiple workers need to share results often enough to justify the service, access-control, and upload-policy overhead.
The Smallest Setup That Works
A remote cache needs only two things: a backend and one flag. The backend side is broad: any properly configured HTTP/1.1 server that supports PUT and GET can serve Bazel's cache protocol, and common options include bazel-remote, nginx, and object-store-backed services such as GCS.1 If you want the simplest purpose-built server on your own infrastructure, bazel-remote is the usual OSS choice: it stores data on disk, supports both REST and gRPC cache APIs, and includes garbage collection to keep storage bounded.5
The client side is just --remote_cache=. For a simple policy where CI writes and developers only read, a checked-in .bazelrc can be as small as:
build:ci --remote_cache=https://cache.example.com
build:dev --remote_cache=https://cache.example.com
build:dev --remote_upload_local_results=false
--remote_cache enables the shared cache. --remote_upload_local_results=false turns the client into a read-only consumer, which is the recommended way to keep write access narrow.6 HTTP and HTTPS work, and Bazel also accepts grpc and grpcs endpoints when your backend exposes those protocols instead.6 The ci-cache-baseline .bazelrc keeps these same lines as commented-out placeholders so the runnable example does not require a backend until a real endpoint, credentials, and a write policy actually exist.
For a concrete server route, the bazel-remote repository map
starts with its standalone AC/CAS contract and then points to focused
Docker Compose,
Kubernetes,
and systemd deployments.7 When an endpoint or error depends on protocol
semantics rather than this server's configuration, move from that operational
example to the authoritative
remote_execution.proto
through the Remote APIs repository map.8
Why the CI-Writes / Developers-Read Policy Matters
A shared cache multiplies good outputs, but it also multiplies bad ones. If a build action depends on something Bazel did not track correctly, one machine can upload an artifact that other machines will happily reuse. The classic example is an undeclared input: the build may "work" once, then spread a wrong result to every developer who shares the cache.4 Bazel's sandboxing reduces that risk substantially, but it does not make shared cache writes a free-for-all.4
That is why it pays to be careful about who can write to the remote cache, and why the simplest policy is still the best one for most teams: CI writes, everyone else reads.6 Keep the upload side tied to the environment you already treat as canonical, and let developer machines consume those artifacts without becoming another source of truth.
If developers already benefit from 3.6.4 Disk Cache in CI, do not think of remote cache as a replacement. Bazel can use both at once. With --disk_cache and --remote_cache set together, it forms a combined cache that reads and writes both local disk and the shared remote store.2 That preserves fast local branch-switch workflows while still letting other machines reuse the same work.
Why Disk Cache and Remote Cache Feel So Similar
They are built on the same model. The remote cache has two stores: the Action Cache (AC), which maps an action key to an ActionResult, and the Content Addressable Store (CAS), which holds the actual output files by digest.1,9 Bazel's disk cache uses the same remote-cache concepts locally, which is why moving from --disk_cache to --remote_cache feels like changing the cache's location rather than learning a brand-new feature.2,9
A remote cache helps when the expensive part is re-executing unchanged actions on a different machine. It does not replace the server-state discussion in 3.6.2 Bazel Server Lifecycle in CI. Use it when execution work repeats across runners, then go deeper into protocol details, backend trade-offs, and cache isolation in 6.2 Shared Remote Cache.
Remote cache is the next step after --disk_cache when the cache boundary becomes the machine. Start with a single shared endpoint, let CI write, let developers read, and keep expectations realistic about what cache layer it accelerates. When you need protocol internals, namespace isolation, or production monitoring, continue in 6.2 Shared Remote Cache.
Check your understanding · 3 questions
1.Why is a CI-writes / developers-read policy recommended for shared remote cache write access?
Select one answer
2.True or false about remote cache setup:
Choose True or False for each sentence
3.A team already uses --disk_cache on developer machines. They now want cross-runner sharing in CI. What is the recommended approach?
Select one answer
Footnotes
-
Remote Caching — remote cache as a shared backend, supported transports and backends, CI-only write guidance, and the note that CI containers still lose in-memory state ↩1 ↩2 ↩3
-
Bazel's Remote Caching and Remote Execution Explained —
--remote_cache, combined cache with--disk_cache, and the lookup/execute/upload flow through AC and CAS ↩1 ↩2 ↩3 -
How Bazel built its CI system on top of Buildkite — stateless workers cannot rely on local caches. Remote cache and
bazel-remoteas the next step ↩ -
Setting up a shared build cache using Bazel — why teams move from local to shared cache, benefits for CI/developers, and how cache poisoning spreads when inputs are undeclared ↩1 ↩2 ↩3
-
Remote Caching —
bazel-remoteas a purpose-built cache server with disk storage, garbage collection, and REST/gRPC support ↩ -
Remote Caching —
--remote_cache,--remote_upload_local_results=false, supportedhttp/https/grpc/grpcsschemes, and the recommendation to restrict write access ↩1 ↩2 ↩3 -
bazel-remote repository map — the README and focused deployment files provide a purpose-built path from one cache process to a shared service ↩
-
Remote APIs repository map — the versioned Remote Execution proto is the authoritative AC, CAS, ByteStream, capability, and execution contract ↩
-
The Many Caches of Bazel — AC/CAS roles in the remote cache and disk cache as the same model used locally ↩1 ↩2