Language toolchains & SDKs

How to Clean Bazel's Disk and Repository Cache (bazel clean --expunge)

If you work on a large monorepo or build infrastructure on a Mac, you already know how aggressively Bazel caches everything. Running a bazel clean disk cache is often the fastest way to reclaim multiple gigabytes that have quietly accumulated under ~/.cache/bazel and your project's output base. This guide covers every layer of Bazel's caching architecture, shows you exactly which commands and folders to target, and explains how to decide what is actually safe to delete.

How Bazel's Caching Architecture Works on macOS

Bazel separates its storage into several distinct locations. Understanding them is essential before you delete anything, because each layer serves a different purpose and has a different cost to rebuild.

  • Output base — per-workspace directory holding the build graph, action cache, and all build artifacts. Located inside ~/.cache/bazel/_bazel_<username>/<hash>/ by default.
  • Repository cache — a shared, cross-workspace archive of external dependencies downloaded via http_archive, maven_jar, and similar rules. Stored at ~/.cache/bazel/_bazel_<username>/cache/repos/v1/ unless you override --repository_cache in your .bazelrc.
  • Disk cache — an optional content-addressable cache shared across workspaces, typically pointed at a path like ~/.cache/bazel-disk-cache via --disk_cache in your .bazelrc. Not created by default; it only exists if your project or CI config enables it.
  • Remote cache artifacts — not stored locally; these live on a remote server. Cleaning local folders has no effect on remote cache state.

On Apple Silicon Macs running macOS Sequoia (15) or Tahoe (16), paths are identical to Intel Macs because Bazel follows $HOME. The key difference is that native arm64 builds produce arm64 artifacts, so a cross-arch output base will not share artifacts with a native one.

Where Bazel Stores Its Cache on Mac — Folder Reference

Cache layer Default path on macOS Typical size Safe to delete?
Output base (build artifacts) ~/.cache/bazel/_bazel_<user>/<hash>/ 1 – 30 GB per workspace Yes — rebuilds from source
Repository cache ~/.cache/bazel/_bazel_<user>/cache/repos/v1/ 500 MB – 5 GB Yes — re-downloads on next build
Disk cache (if configured) Custom path in .bazelrc, e.g. ~/.cache/bazel-disk-cache 1 – 50 GB Yes — actions re-execute to repopulate
Install base ~/.cache/bazel/_bazel_<user>/install/ 100 – 400 MB Yes — Bazel re-extracts on next run
Bazel server JVM Inside the output base (symlinked) Minimal Removed automatically by --expunge

How to Clean Bazel's Disk Cache Step by Step

The following steps start with the least destructive option and escalate to a full wipe. Work through them in order so you only rebuild what you need to.

  1. Check how much space Bazel is using. Open Terminal and run:
    du -sh ~/.cache/bazel
    This gives you the total size of all output bases and the repository cache. If you configured a separate disk cache, check that path too:
    du -sh ~/.cache/bazel-disk-cache
  2. Run bazel clean inside the workspace. Navigate to your project and run:
    cd ~/your-project && bazel clean
    This removes the bazel-out symlink contents and clears build artifacts for the current workspace only. The repository cache and disk cache are untouched. Next build re-executes actions but reuses cached downloads.
  3. Add --expunge for a complete output-base wipe.
    bazel clean --expunge
    This shuts down the Bazel server, deletes the entire output base directory (artifacts, action cache, install base), and removes the server socket. The repository cache is still preserved, so external dependencies do not need to be re-downloaded.
  4. Delete the repository cache manually. There is no bazel flag that targets the repository cache alone; you remove it directly:
    rm -rf ~/.cache/bazel/_bazel_$(whoami)/cache/repos/v1
    The next build re-downloads every http_archive dependency. This is safe but can be slow on large monorepos with many external rules.
  5. Wipe the disk cache directory (if you use one). Find the path in your .bazelrc or user.bazelrc — look for a line containing --disk_cache — then delete the folder:
    rm -rf ~/.cache/bazel-disk-cache
    Bazel recreates the directory on the next build and begins repopulating it.
  6. Nuke everything in one shot. If you want a completely fresh slate:
    bazel clean --expunge && rm -rf ~/.cache/bazel
    This removes all output bases across all workspaces and the shared repository cache. Use this when switching Bazel versions or diagnosing persistent corruption.

Using --expunge_async for Large Caches

If your output base is very large (tens of gigabytes), bazel clean --expunge can block your terminal for minutes. The async variant hands deletion off to the OS and returns immediately:

bazel clean --expunge_async

Bazel starts the next server immediately. The old output base is moved to a temporary path and deleted in the background. Check that the deletion has finished with du -sh ~/.cache/bazel before kicking off a new build on a space-constrained disk.

Cleaning Other Build-Tool Caches That Live Near Bazel

Bazel projects often pull in rules for other ecosystems, and those ecosystems leave their own footprints. If your monorepo uses rules_jvm_external, you may also have a Maven local repository at ~/.m2/repository. If it uses rules_go or a Gazelle setup that shells out to go, the Go module cache lives at $(go env GOPATH)/pkg/mod, which defaults to ~/go/pkg/mod. Rust rules backed by Cargo leave artifacts under ~/.cargo/registry and ~/.cargo/git.

None of these are removed by bazel clean --expunge because Bazel treats them as external environment state rather than its own output. You manage them with their own toolchain commands: go clean -modcache, cargo cache --autoclean, or mvn dependency:purge-local-repository. For a broader picture of what is consuming space across all your developer toolchains, see our guide on what is taking up space on your Mac.

Configuring Bazel to Limit Future Cache Growth

Rather than letting caches grow indefinitely and cleaning manually, you can apply size limits in your .bazelrc.

Capping the disk cache

Add the following to ~/.bazelrc or your project's .bazelrc:

build --disk_cache=~/.cache/bazel-disk-cache
build --experimental_disk_cache_gc_max_size=10g

Bazel will garbage-collect the oldest entries once the disk cache exceeds 10 GB. Adjust the limit to suit your available storage.

Setting a repository cache path explicitly

If you share a machine with other developers or use multiple user accounts, pointing all of them at a single shared repository cache saves redundant downloads:

common --repository_cache=/Users/Shared/bazel-repo-cache

Create the directory and make it world-writable, or group-writable for a shared dev group, before setting this flag.

How Much Space Can You Expect to Recover?

The answer depends entirely on your project size and how long you have been building. On a year-old MacBook used for active monorepo development, it is not unusual to find:

  • 10 – 25 GB in the output base (more if you build multiple configurations such as -c opt and -c dbg)
  • 2 – 8 GB in the repository cache, especially for Java or Python projects with many transitive dependencies
  • 5 – 50 GB in the disk cache if CI has been seeding it from a shared remote

A full expunge plus manual cache deletion can realistically recover 20 – 60 GB on a well-used machine. If you want to audit these folders alongside Xcode derived data, npm caches, and other toolchain artifacts before committing to deletion, a tool like Crumb can scan all of them at once and show you exactly what is safe to remove.

For context on how Bazel's output base compares to Xcode's own derived data bloat, the deep dive on why Xcode takes up so much space walks through the same pattern of aggressive caching with clear deletion steps.

Troubleshooting Common Errors

"Output base is in use" when running --expunge

Another Bazel server may still be running for that workspace. Run bazel shutdown first, then retry bazel clean --expunge. If the error persists, find and kill the Java server process with pkill -f "bazel(d|server)" and try again.

Bazel recreates a huge cache immediately after cleaning

This usually means a CI script or local daemon is running a full build in the background. Check Activity Monitor for Java processes associated with Bazel and verify that no ibazel or Bazel Watch jobs are active before cleaning.

Permission denied when deleting ~/.cache/bazel

The Bazel server process owns files inside the output base. Run bazel shutdown or use bazel clean --expunge (which shuts the server down first) rather than deleting the directory directly with rm -rf while the server is running.

Reclaim your disk in one click

Crumb audits your whole Mac, tells you what's safe to delete, and frees the space in seconds — private, local, and Apple-notarized.

Download Crumb for macOS

Frequently asked questions

Is it safe to delete the Bazel disk cache on Mac?
Yes. The disk cache is a pure performance optimization — Bazel recreates it automatically as you build. Deleting it means your next build will execute all actions from scratch rather than replaying cached results, which takes longer but produces identical output.
What is the difference between bazel clean and bazel clean --expunge?
bazel clean removes build artifacts for the current workspace but leaves the Bazel server, action cache index, and repository cache intact. bazel clean --expunge shuts down the server and deletes the entire output base directory, which is a more thorough reset. Neither command touches the shared repository cache or an external disk cache.
Where exactly is Bazel's cache stored on a Mac?
The default location is ~/.cache/bazel/_bazel_<your-username>/. Inside that directory you will find one or more hash-named folders (output bases, one per workspace) and a cache/repos/v1 folder that is the shared repository cache. If your project enables --disk_cache, that path is set in .bazelrc and may differ.
Will I lose my external dependencies if I delete the repository cache?
You will not lose them permanently, but Bazel will re-download every http_archive and external dependency the next time you build. On a fast connection this typically takes a few minutes. On a metered or slow connection, wait until you have good bandwidth before clearing the repository cache.
How often should I clean Bazel's cache?
Most developers clean only when diagnosing a stale-artifact bug, after a major Bazel version upgrade, or when disk space runs critically low. Routine cleaning is counterproductive because it forces full rebuilds, which negate the speed benefits Bazel is designed to provide.