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
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. Keep this simple setup with a read-write token when you trust the pipeline's users and build code. Ensure actions declare their inputs: a missing input can cause another build to reuse an incorrect result. For builds that should only download outputs, use a read-only token and disable uploads:
# Optional: builds that may read but should not upload
bazel build //... --remote_upload_local_results=false- Give trusted CI a read/write token, one per pipeline or repository, so a poisoned entry is attributable to a single writer.
- Trusted developer machines and pull requests can use read-write tokens too. Use a read-only token for untrusted builds that may download private outputs, or no token when they should not access those outputs.
- 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
Follow the Bazel GitHub Actions recipe or choose another provider in CI setup.
The Bazel remote cache guide explains how the action cache and CAS work together. If Bazel never seems to hit, see troubleshooting.