Faster Bazel builds with remote cache banner
6 min read
guides

Stay in the loop

Get notified when we ship new posts.

Faster Bazel builds with remote cache

Remote caching in Bazel is about sharing work you've already done. If CI has built a target, you want your laptop to reuse that result. If a developer builds it first, you want CI and the rest of the team to benefit too.

Depot Cache gives your team and CI a shared Bazel cache without having to run your own cache server. Point both at https://cache.depot.dev and authenticate to the same Depot organization. When the build inputs and configuration produce the same action key, Bazel downloads the existing output instead of building it again. Anything that isn't cached still builds on the machine running Bazel.

Share one Bazel cache between local builds and CI

If you already have a Bazel project, you need a cache endpoint and a Depot API token. Developers and CI can use their own tokens, as long as they're authorized for the same Depot organization.

Commit the cache endpoint

Start by adding the cache endpoint to your repository's .bazelrc. Commit this file so everyone on the team, including CI, uses the same configuration:

build --remote_cache=https://cache.depot.dev

Keep tokens out of this file. If you're using a user token that belongs to multiple organizations, also specify the organization whose cache you want to use:

build --remote_header=x-depot-org=YOUR_DEPOT_ORG_ID

Replace YOUR_DEPOT_ORG_ID with the organization ID. Use that same organization in CI. See the Bazel integration docs for authentication details.

Run a local build

Make your token available as the DEPOT_TOKEN environment variable through your local secret manager or shell session. From the repository root, run:

bazel build \
  --remote_header="authorization=${DEPOT_TOKEN:?Set DEPOT_TOKEN first}" \
  //...

The shell fills in the token when you run the command. Keep that part out of the committed .bazelrc; putting ${DEPOT_TOKEN} there won't expand it like the shell does. //... builds all targets in the workspace, so replace it with the target you normally build if you only need part of the project.

Use the same configuration in CI

Check out the repository and install the Bazel version your project uses. Then run the same command with DEPOT_TOKEN supplied by your CI secret store. For example, this GitHub Actions step goes after checkout and Bazel setup:

- name: Build with the shared Bazel cache
  env:
    DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }}
  run: |
    bazel build \
      --remote_header="authorization=${DEPOT_TOKEN:?Set DEPOT_TOKEN first}" \
      //...

Store the CI token in the repository's DEPOT_TOKEN secret. CI reads the same .bazelrc as your local build and uses its own token to reach the same cache. You can use this with other CI providers too; they just need to supply the environment variable.

We've also integrated Depot Cache with our GitHub Actions runners. Enable Allow Actions jobs to automatically connect to Depot Cache in your organization settings, and we'll provide a $HOME/.bazelrc with the connection details. Once Bazel is installed, you can run bazel build //... without the manual token step above. If you're building inside Docker, you'll need to configure credentials inside the container.

Check that builds reuse the cache

Build a target in CI, then build it from a fresh local checkout using the same commit and build configuration. Look for remote cache hits in Bazel's build summary. Just running the build twice on your laptop isn't enough to check this, because the second build can use outputs already on your machine.

If you're seeing misses, check more than the source code. Different toolchains, target platforms, flags, or environment variables can change the action key. Your macOS laptop and Linux CI job can use the same cache without being able to reuse every result. Bazel's remote-cache troubleshooting guide walks through how to find those differences.

How Bazel's build cache works

When you start a build, Bazel breaks it into a graph of actions. Compiling MyClass.java into MyClass.class is one example. Each action has inputs, a command, environment variables, and expected outputs. Bazel hashes the inputs and configuration into an action key.

On the next build, Bazel checks whether it already has usable local outputs. If it doesn't, it can look up that action key in the remote cache and download the result. Change the inputs and you can get a different key, which means Bazel has to run the action again.

With a writable remote cache, Bazel can upload the new result for the next machine that needs it. That's how compiling something once on a developer's laptop can save CI from compiling it again.

You can run your own cache backend if you're happy managing the storage, authentication, and cleanup. With Depot Cache, we take care of that infrastructure. You configure Bazel and share the cache across your team:

Comparing GitHub Actions Cache and Depot Cache for Bazel builds

To show the difference, we benchmarked building gRPC on GitHub-hosted and Depot runners for the original version of this post in February 2025. We populated the cache from a recent commit, then built a slightly newer one. That gives us an incremental build with partial cache hits, rather than a rebuild where everything is already cached.

40.00 min30.00 min20.00 min10.00 min0.00 min
1.55 min
15.23 min
19.75 min
35.88 min
Depot w/ cacheDepot cachelessGitHub w/ cacheGitHub cacheless

Completion time (lower is better)

The GitHub-hosted runner used actions/cache to restore previously built artifacts. The Depot runner used Bazel's remote cache. For the Depot run without remote caching, we removed the runner's ~/.bazelrc configuration before building.

In that test, Depot with remote caching took 1.55 minutes, compared with 19.75 minutes on GitHub with actions/cache. That's about 12.7x faster, with both the runner and the caching approach changing.

Looking just at Depot, enabling remote caching cut the build from 15.23 minutes to 1.55 minutes, about 9.8x faster. Even without remote caching, the Depot run was about 1.3x faster than GitHub's cached run.

Those are the results from the original benchmark. How much time you save on your own build depends on what Bazel can reuse and how long it takes to download those outputs. Try the same targets locally and in CI, then look at the remote cache hits and build time. You want the next machine to pick up the work the first one already did.

Share your Bazel build cache with your team and CI. We'll handle the cache infrastructure.

Try Depot Cache

Start building with Depot
in minutes