メインコンテンツまでスキップ

Configuring the build cache for Bazel in local builds

You can use the Bitrise Build Cache for local Bazel builds too. Your local builds then read from the same cache as your CI builds, so an action your CI already ran doesn't have to run again on your machine.

The Bitrise Build Cache CLI sets this up for you by writing the cache flags to your ~/.bazelrc.

Before you startClick to copy link

Ensure you have:

  • A working Bazel project on your machine, on Bazel 6 or later. The setup uses Bazel's credential helper support, which earlier versions don't have.
  • A Bitrise workspace with the Build Cache enabled. Check it on the Build Cache page.
Activation is global, not per-project

activate bazel writes a single block to ~/.bazelrc in your home directory. It never touches your project's .bazelrc.

Every Bazel project on your machine picks up the cache flags, not just the one you activated from. The repository URL reported to the dashboard is read from the git remote of the directory you ran the activation in, so on a machine with several Bazel projects they all report the first one. That affects dashboard attribution only, not cache correctness. Re-run the activation from another project's directory to change it.

Installing the CLIClick to copy link

Install the CLI with Homebrew (recommended):

brew install bitrise-io/bitrise-build-cache/bitrise-build-cache

Or, without Homebrew:

curl --retry 5 -sSfL \
'https://raw.githubusercontent.com/bitrise-io/bitrise-build-cache-cli/main/install/installer.sh' \
| sh -s -- -b ~/.local/bin

Make sure the install location is on your PATH, then check the install:

bitrise-build-cache --version

Keep the CLI on your PATH afterwards. Bazel runs the CLI on every build to fetch a fresh auth token, not only during setup.

Activating the cacheClick to copy link

Run the interactive wizard:

bitrise-build-cache activate --interactive

The wizard asks for the following:

  1. Sign in to Bitrise: opens your browser for authentication on the first run. The CLI stores the credentials in the OS keychain and refreshes them automatically, so later runs skip this step. On a machine without a usable keychain, the CLI falls back to storing them in a config file.
  2. Select a workspace: pick the workspace whose Build Cache you want to use. The CLI selects it automatically if you only have access to one.
  3. Which build tools should I set up: ensure Bazel is selected. Use space to toggle an option and enter to confirm.
  4. Display name for this machine's local invocations: the name your local builds show up under in the Build Cache dashboard, for example local-<yourhandle>.
  5. Enable cache push: select No, pull only. See Local builds only read from the cache.

The non-interactive equivalent, once you have signed in:

bitrise-build-cache activate bazel --cache

What the activation writesClick to copy link

A single marked block appended to ~/.bazelrc. Existing content is preserved, and re-running the activation only updates the block:

# [start] generated-by-bitrise-build-cache
build --credential_helper=*.services.bitrise.io=bitrise-build-cache
build --remote_cache=grpcs://bitrise-accelerate.services.bitrise.io
build --remote_timeout=600s
build --remote_header=x-flare-buildtool=bazel
build --remote_header=x-flare-builduser=
build --noremote_upload_local_results
build --bes_backend=grpcs://flare-bes.services.bitrise.io:443
build --bes_results_url=https://app.bitrise.io/build-cache/invocations/bazel/
build --bes_timeout=2m
build --bes_upload_mode=wait_for_upload_complete
build --build_event_publish_all_actions
build --show_timestamps
build --remote_header='x-org-id=<workspace-id>'
build --bes_header='x-org-id=<workspace-id>'
build --remote_header='x-repository-url=https://github.com/<org>/<repo>.git'
build --bes_header='x-repository-url=https://github.com/<org>/<repo>.git'
build --bes_header='x-os=<detailed OS info>'
build --bes_header='x-locale=C'
build --bes_header='x-default-charset=UTF-8'
build --bes_header='x-cpu-cores=4'
build --bes_header='x-mem-size=16759259136'
# [end] generated-by-bitrise-build-cache

Two lines worth highlighting:

  • --credential_helper points at the CLI rather than storing a token, so Bazel fetches a fresh one on every build and an expiring login keeps working. This is why the CLI has to stay on your PATH.
  • --noremote_upload_local_results is pull-only mode. Activating with --cache-push writes --remote_upload_local_results instead.

The x-os, x-cpu-cores, x-mem-size, x-locale, and x-default-charset headers describe your machine and are used for analytics only, and don't affect cache keys. They matter if you commit the configuration, because they're specific to the machine that generated the block. See What is safe to commit.

Verifying the setupClick to copy link

Run the CLI's health check:

bitrise-build-cache doctor

It reports the status of every part of the local setup and ends with an overall verdict. The probes for the other build tools report as skipped:

Bitrise Build Cache - doctor
CLI version: 3.x.y

Healthy:
✓ auth OAuth login (keychain) (workspace <id>), token valid until <iso-timestamp>
✓ keychain-smoke Set/Get/Delete round-trip OK
✓ auth-backend latency <ms>, source=keychain, workspace=<id>
✓ xcelerate-proxy skipped (xcode not activated)
✓ xcelerate-wrapper-path skipped (xcode not activated)
✓ xcelerate-enrichment skipped (xcode not activated)
✓ ccache-helper skipped (c++ not activated)
✓ ccache-binary skipped (c++ not activated)
✓ log-dirs no activated tool writes logs

Overall: ok

To let the CLI repair the issues it can fix on its own, run bitrise-build-cache doctor --fix --interactive.

Running a buildClick to copy link

  1. Run bazel clean first. Bazel's local action cache sits in front of the remote cache, so if a target is already built locally, Bazel serves it from disk and never contacts Bitrise - and you see no evidence that the remote cache works.

    cd path/to/your/bazel/project
    bazel clean
  2. Build your target:

    bazel build //your/target:name

A build that hits a warm cache ends like this:

(16:47:35) INFO: Invocation ID: <invocation-id>
(16:47:35) INFO: Streaming build results to: https://app.bitrise.io/build-cache/invocations/bazel/<invocation-id>
(16:47:36) INFO: Analyzed target //src/close-matching-prs:close-matching-prs (91 packages loaded, 9216 targets configured).
(16:47:36) INFO: Found 1 target...
(16:47:36) INFO: Elapsed time: 0.934s, Critical Path: 0.18s
(16:47:36) INFO: 11 processes: 4 remote cache hit, 7 internal.
(16:47:36) INFO: Build completed successfully, 11 total actions

Checking that it workedClick to copy link

The summary line is the proof. It reads differently in each of the three cases:

Summary lineWhat it means
11 processes: 4 remote cache hit, 7 internal.Working. The actions were fetched from the Bitrise Build Cache.
1 process: 4 action cache hit, 1 internal.Served from your local cache. The remote cache was never contacted, so run bazel clean first.
11 processes: 7 internal, 4 processwrapper-sandbox.Built locally from scratch. Either the cache has no entries for this target, or authentication failed. Look for WARNING: Remote Cache: UNAUTHENTICATED earlier in the output.

internal actions, such as symlinks and file writes, are never cacheable. The ratio that matters is remote cache hits against the actions that aren't internal.

SignalWhere to find itWhat success looks like
INFO: N processes: X remote cache hitBazel build summaryA non-zero remote cache hit count after a bazel clean
INFO: Streaming build results to:First and last lines of the buildA link to the invocation is printed
DashboardThe printed link, or the Build Cache pageA row appears under your display name, with the same hit counts

Local builds only read from the cacheClick to copy link

The setup in this guide activates the Build Cache in pull-only mode: your local builds read from the shared cache but never write to it. This is the recommended mode for local development.

Build tools recommend writing cache entries only from an environment where the source files don't change during the build. On a local machine you might keep editing files while a build is running, which can produce cache entries that don't match their inputs, and those entries would then be served to your teammates and to CI. Pull-only removes that risk: a broken local build can't affect anyone else.

The usual pattern is to have CI populate the cache, because CI builds from a clean, fixed checkout, and to let local machines pull from it.

Pushing to the cache from local buildsClick to copy link

Pull-only assumes that something else fills the cache, which is normally CI. If nothing does, your local builds have nothing to read: the summary line keeps reporting 0 remote cache hit.

If your team doesn't run the Build Cache on CI, turn pushing on for your local builds and leave it on. Your machine then populates the cache as you work, for you and for your teammates.

Re-run bitrise-build-cache activate --interactive and answer Yes, push too at the cache push prompt when you run the wizard, or run the non-interactive activate command:

bitrise-build-cache activate bazel --cache --cache-push

You can check which mode you're in without running a build:

grep upload_local_results ~/.bazelrc
# --noremote_upload_local_results → pull-only
# --remote_upload_local_results → push enabled
注記

An entry written from a build whose source files changed while it was running can be wrong, and your teammates read the same entry. Avoid editing files during a build you push from.

Setting up the Build Cache on CI is the more robust option, because CI builds from a clean, fixed checkout. Once it runs there, switch your machine back to pull-only.

Committing the configuration to your repositoryClick to copy link

Bazel already reads a .bazelrc from your workspace root, so the cache flags can be committed to the repository instead of being generated on every machine. Onboarding a dev machine then comes down to installing the CLI and signing in:

brew install bitrise-io/bitrise-build-cache/bitrise-build-cache
bitrise-build-cache auth login

How the files combineClick to copy link

Bazel reads its configuration files in this order, and the last value wins for a single-valued flag:

  1. The system file, /etc/bazel.bazelrc
  2. The workspace file, <repo>/.bazelrc (the committed one)
  3. The home file, ~/.bazelrc (what the activation writes, if it was ever run)
  4. Command-line flags

So the home file takes precedence over the committed one, and command-line flags beat both. Add --announce_rc to a build to see what Bazel actually loaded.

Commit pull-only and let CI opt into pushClick to copy link

A developer who only installs the CLI and runs auth login never gets a ~/.bazelrc, so there is nothing to override the committed block. Whatever you commit is what they build with, so commit the safe mode:

build --noremote_upload_local_results

On CI, run the activation with pushing enabled before the build. Because the home file beats the committed workspace file, it overrides the committed pull-only flag on that machine only:

bitrise-build-cache activate bazel --cache --cache-push

That gives you the split with no per-developer setup: the committed file is the pull-only default everyone inherits, and the one environment that should write to the cache is the one that runs the activation.

What is safe to commitClick to copy link

LinesCommitWhy
--remote_cache, --remote_timeout, --bes_backend, --bes_results_url, --bes_timeout, --bes_upload_mode, --build_event_publish_all_actions, --show_timestampsYesIdentical on every machine
--remote_header='x-org-id=…' and the matching --bes_headerYesWorkspace-wide, not machine-specific
--remote_header='x-repository-url=…' and the matching --bes_headerYesIt identifies this repository
--noremote_upload_local_resultsYes, in the pull-only formEvery developer who only runs auth login inherits it. CI flips it by running the activation with --cache-push
--credential_helper=*.services.bitrise.io=bitrise-build-cacheYes, after checking the valueIt's the bare binary name, which Bazel looks up on PATH. If the activation ran on a machine where the CLI wasn't on PATH, the CLI writes an absolute path instead. Don't commit that form
--bes_header='x-os=…', x-cpu-cores, x-mem-size, x-locale, x-default-charsetNoPer-machine, and x-os contains your hostname. They're analytics only and don't affect cache keys, but committing them attributes everyone's builds to your machine
--remote_header=authorization="Bearer …"NeverA live credential. It only appears in a block generated on CI

What happens without the CLI installedClick to copy link

If you commit the --credential_helper line, a teammate who hasn't installed the CLI can't build at all. Bazel looks the helper up on PATH, doesn't find it, and fails while initializing the remote cache:

ERROR: Could not find file with name 'bitrise-build-cache' on PATH '...'
ERROR: Could not find file with name 'bitrise-build-cache' on PATH '...'
ERROR: Could not find file with name 'bitrise-build-cache' on PATH '...'
ERROR: Error initializing RemoteModule

Bazel exits with code 2 and no targets are built. There's no fallback to a local build, because the failure happens before the build starts.

Installing the CLI and running bitrise-build-cache auth login on that machine resolves it.

Remote Build ExecutionClick to copy link

If Remote Build Execution is enabled for your workspace, you can use it locally by adding the --rbe flag to the activation. You need the workers set up for your workspace and the pool configuration in your repository's .bazelrc first. See Remote Build Execution for Bazel.

TroubleshootingClick to copy link

Start with the CLI's health check. It inspects every part of the local setup and repairs the issues it can fix on its own:

bitrise-build-cache doctor --fix --interactive

If you're still experiencing issues, check the following table:

IssueFix
The wizard reports that it needs a terminalRun TERM=dumb bitrise-build-cache activate --interactive for line-based mode.
The build reports action cache hit instead of remote cache hitRun bazel clean so Bazel has to fetch from the remote cache.
The build fails with Could not find file with name 'bitrise-build-cache' on PATHThe CLI isn't installed, or isn't on your PATH. Install it, then run bitrise-build-cache auth login.
The build fails while fetching credentials, naming the credential helperThe CLI is installed but has no credentials. Run bitrise-build-cache auth login.
doctor reports a problem it can't fixRe-run it with --debug for the full context.