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_cachein your.bazelrc. - Disk cache — an optional content-addressable cache shared across workspaces, typically pointed at a path like
~/.cache/bazel-disk-cachevia--disk_cachein 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.
-
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 -
Run
bazel cleaninside the workspace. Navigate to your project and run:cd ~/your-project && bazel clean
This removes thebazel-outsymlink 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. -
Add
--expungefor 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. -
Delete the repository cache manually. There is no
bazelflag that targets the repository cache alone; you remove it directly:rm -rf ~/.cache/bazel/_bazel_$(whoami)/cache/repos/v1
The next build re-downloads everyhttp_archivedependency. This is safe but can be slow on large monorepos with many external rules. -
Wipe the disk cache directory (if you use one). Find the path in your
.bazelrcoruser.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. -
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 optand-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.