Bazel remote cache setup
Cachely speaks the Bazel HTTP remote cache protocol, serving both the action cache and the content-addressable store. Point --remote_cache at the bare host and Bazel appends the rest.
Configure
Put the cache URL in your committed .bazelrc - Bazel appends /ac/ and /cas/ itself - and keep the token in a gitignored user.bazelrc pulled in via try-import. Bazel cannot read .env files, so this is its dotenv equivalent:
# .bazelrc (committed)
build --remote_cache=https://remote.cachely.dev
# Read the cache everywhere, upload from trusted CI only.
# (--noremote_upload_local_results is the same flag, negated form.)
build --remote_upload_local_results=false
build:cachely-ci --remote_upload_local_results=true
try-import %workspace%/user.bazelrc# user.bazelrc (gitignored - carries the raw token)
build --remote_header="Authorization=Bearer <YOUR_TOKEN>"In CI, skip user.bazelrc and pass the header on the command line from your secret store, e.g. bazel build //... --remote_header="Authorization=Bearer $CACHELY_TOKEN". HTTP Basic via .netrc also works - use the token as the password (the username is ignored).
Who is allowed to write
Bazel can upload locally produced action results, and it does so by default. We recommend turning that off until your builds are demonstrably hermetic: an action key that misses an input - an absolute path, a host tool, an environment value, a file edited mid-build - lets one machine publish a result that every other machine then replays. The committed .bazelrc above is therefore read-only for everyone, and trusted CI opts back in per invocation:
# Trusted CI (protected branch, its own read/write token)
bazel build //... --config=cachely-ci- Give trusted CI a read/write token, one per pipeline or repository, so a poisoned entry is attributable to a single writer.
- Give developer machines, pull requests, and fork builds a read-only token - or no cache credentials at all. They still get every cache hit.
- Treat a self-hosted runner as trusted only if it is isolated per repository; otherwise give it a read-only token.
- Rotate or expire writer tokens, and revoke a writer immediately if you suspect a poisoned entry.
The flag is guidance, the token is the boundary
Bazel applies .bazelrc lines in order, an imported user.bazelrc comes after the committed file, and the command line wins over both - so anyone can re-enable uploads locally. A read-only token is the part that actually holds: Cachely rejects every write from it with a 403, on /ac/ and /cas/ alike. See tokens and access control.
Next
The Bazel remote cache guide explains how the action cache and CAS work together. If Bazel never seems to hit, see troubleshooting.