Skip to main content
Bazel keeps one output base per workspace path, and the download cache, forever. Delete a git worktree and its output base, with its external/ tree and action cache, stays behind. aspect gc removes what nothing is using.

What it removes

Each period takes 0: the grace period to remove orphans immediately, the idle cutoffs to turn their rule off. Everything removed is re-creatable: a removed output base costs a cold build, a pruned download one re-fetch. “Last used” is when a Bazel server last started or ran a command in the base. A download-cache entry’s last use is the newer of its mtime and atime, since Bazel touches the mtime on every cache hit.

What it keeps

  • An output base with a running Bazel server, unless it is orphaned. An orphan’s server is stopped before its base is removed.
  • An output base a process may be serving that ps cannot identify, as on an image without procps.
  • An aspect worktree pool slot’s base, which is not treated as orphaned: a free slot has no worktree on purpose, and that base is what makes its next lease warm.
  • The exception is a slot nothing will lease again, its directory gone and its pool holding no record of it. That base is an orphan like any other.
  • A pool slot’s base still goes by idle time, a leased slot’s included, since --base-max-idle-days measures Bazel’s use of the base and not whether a checkout is open. A removed base costs that slot a cold build, never its checkout.
  • Anything under the output user root that is not named like an output base, such as install/ and cache/.

Removing specific output bases

Name output bases to remove them instead of applying the rules, whatever their state. Each is a hash or a path under the output user root, and any number can be named at once. A running server in a named base is stopped first. The download cache is left alone, and no census is printed; the JSON still carries the policy, with no download-cache entries.
aspect output-bases lists the hashes.

Removing every output base

--all removes every output base under the output user root, whatever its state — live, idle, orphaned, within the grace period, aspect worktree pool slots, undetermined and trash — as if each were named. A running Bazel server in one is confirmed as that base’s own and stopped first; the listing, the prompt and --dry-run say which, and mark the server of the workspace you run it from. A process ps cannot identify fails that base’s removal rather than being killed.
It never touches aspect worktree checkouts, leases or registries — a pool slot just starts cold — nor install/ or cache/repos/v1/contents, and the download cache keeps its --download-cache-max-idle-days rule. Only a directory holding one of DO_NOT_BUILD_HERE, execroot/, server/ or lock is taken; any other md5-named entry is listed as kept, and a root where none holds any, with no install/ beside them — an install/ directory passed as the root, say — is refused. --all cannot be combined with named bases. Off a terminal it needs --force; on one, the prompt states what it will do: “Remove all 58 Bazel output bases (91.2 GB), stopping 12 running Bazel servers?”

Confirmation

gc lists everything it will remove, with sizes, then asks. --force answers yes in advance and is required when stdin is not a terminal, so a gc in CI or cron states that it deletes.
Each base is checked again just before it is removed and left alone if Bazel used it after the scan, so a build started while the prompt waited keeps its output base.

JSON

--output=json writes one document to stdout: the output user root, the policy, a count per state (pooled counting pool slots that are neither idle nor orphaned), each removal with its state, kb and outcome (reaped, skipped, failed, or not attempted under --dry-run or when the prompt is declined) and, where its base had a running server, server_stopped, download-cache totals, and what was freed. all says whether --all was given. kept lists the entries left alone as not output bases; both keys are always present, and kept is empty rather than absent when there is nothing to report. The exit code is non-zero when anything could not be removed. A run refused for want of --force off a terminal writes no document.
Paths are shown here with ~; the document carries them in full.

Flags