1.1.6 bazel clean

bazel clean discards local build state for one workspace. Plain clean removes the current workspace's build outputs and action-cache metadata. --expunge goes further by deleting the entire outputBase and stopping the Bazel server.1,2 Use these commands for recovery or disk space rather than as a routine daily step.1,3,4

What Plain clean Removes

bazel clean operates on the output tree. It clears the on-disk action cache, removes the workspace's execroot tree, and deletes workspace symlinks such as bazel-bin, bazel-out, and bazel-testlogs.2 In Level 0 terms, it wipes the local artifact view from 0.1.4 Output Root and forces Bazel to regenerate those workspace-local results on the next build.2

bazel clean

Plain clean is the smaller hammer: it removes this workspace's action working tree and corresponding on-disk action metadata without purging machine-wide caches.1,2

What --expunge Adds

bazel clean --expunge is much more destructive: instead of cleaning only the action cache, execroot, and symlinks, it removes the whole outputBase tree.1,2 That tree includes outputs, server files, execroot/, external/, and the other workspace-local state under $(bazel info output_base).2 Because the Bazel server for this workspace lives there, --expunge also stops the server, making it the equivalent of deleting the whole working tree for that Bazel instance and dropping the warm daemon at the same time.1,2

bazel info output_base
bazel clean --expunge
extra

--expunge_async does the same full expunge in the background. It is safe to invoke another Bazel command from the same client while that cleanup continues, though the overlap may introduce I/O contention.1

Choose the narrowest reset that matches the problem:

  • bazel shutdown when you only want to drop the warm server from 1.1.3 Server/Client Architecture.
  • bazel clean when you want to reclaim this workspace's local outputs.
  • bazel clean --expunge when you need to remove the whole outputBase.

That distinction matters because Bazel can often reuse valid outputs after shutdown, while clean and especially --expunge deliberately throw away more local state.1,5,6

Why It Should Not Be Routine

Turning bazel clean into ritual wastes useful state. The command exists primarily for reclaiming disk space or recovering when incrementality seems wrong. If you ever get a different answer only after cleaning, that is a bug to report rather than a reason to normalize cleaning.1 The same holds operationally for CI: Bazel does not need clean builds for correctness, so CI should not be configured to clean before every build or test run.3

A warm Bazel workflow depends on state that clean or --expunge destroys. 1.1.3 Server/Client Architecture already introduced the in-memory analysis cache held by the server, and bazel clean is one concrete way to invalidate that warm state and make the next build slower.6 The output tree is a separate cache layer on disk: Bazel can still reuse valid results there after bazel shutdown, but clean removes that local reuse path on purpose.5

For Bazel, [Pull] -> [Build] is the healthy loop, while [Clean] -> [Pull] -> [Build] throws away incrementality for no correctness benefit.4 Later, 3.6.1 Basic CI Recipe and 3.6.4 Disk Cache in CI turn that idea into concrete CI patterns.

clean Has A Workspace-Local Scope

The repository cache is a different filesystem tree. By default it lives under ~/.cache/bazel/_bazel_$USER/cache/repos/v1/ and is shared across workspaces and Bazel versions.7 It caches downloads, while the output tree and the in-memory server state are separate layers with different lifetimes.5

That is why <a class="cross-ref" href="/book/1~1~7" title="1.1.7 bazel info"><span class="cross-ref-id">1.1.7</span> bazel info</a> is often the right debugging companion to clean. bazel info output_base tells you which workspace-local tree clean and --expunge are about, while bazel info repository_cache points at a separate shared download cache.2,7 Later, 2.4.2 Where Bazel Caches Things gives the fuller taxonomy.

key takeaway

bazel clean is a reset button, not a daily habit. Plain clean wipes this workspace's output tree and action-cache metadata. --expunge deletes the whole outputBase and stops the server. Use them when you need space or recovery, but if correctness depends on cleaning, the real problem is elsewhere.

Check your understanding · 2 questions

1.Match each reset command to its scope:

Drag each answer onto the matching prompt, or click an answer and then click a prompt

Answers
bazel shutdown
bazel clean
bazel clean --expunge

2.What should you conclude if a build is correct only after bazel clean?

Select one answer

0 of 2 answered

Footnotes

  1. Commands and Optionsclean, --expunge, --expunge_async, disk-space/recovery intent, and the guidance to report incorrect incremental builds instead of normalizing clean 1 2 3 4 5 6 7 8

  2. Output Directory LayoutoutputBase layout, clean clearing the on-disk action cache, removing execroot and workspace symlinks, and --expunge cleaning the whole output base 1 2 3 4 5 6 7 8

  3. FAQ — CI guidance that Bazel does not need clean builds for correctness 1 2

  4. One Weird Trick for Fast CI — practical argument that Bazel CI should preserve incrementality instead of cleaning before each build 1 2

  5. The Many Caches of Bazel — distinction between in-memory server state, output-tree cache, and repository cache 1 2 3

  6. Why is my Bazel build so slow?bazel clean as a concrete cause of losing warm analysis-cache state 1 2

  7. Build programs with Bazel — repository-cache location, sharing semantics, and its role as a separate download cache 1 2