A build machine accumulates every branch anyone has ever pushed
Workspaces, caches and container images pile up on a self hosted runner. What to prune automatically rather than by hand.
A Mac used as a build machine fills faster than any laptop, because it does the work of every developer on the team plus every branch they abandoned. The good news is that it fills in entirely predictable ways, which makes it automatable.
The four things that grow
| What | Why | Prune with |
|---|---|---|
| Workspaces per job | One checkout per job, kept after | A cleanup step, or a retention setting |
| Dependency caches | Restored per job, rarely evicted | A size limit and an age policy |
| Container images | Pulled per build | docker system prune on a schedule |
| Build output and artefacts | Kept in case someone downloads them | Artefact retention settings |
Measure before automating
du -sh ~/actions-runner/_work/* 2>/dev/null | sort -h | tail -15
du -sh ~/.jenkins/workspace/* 2>/dev/null | sort -h | tail -15
docker system dfThe point of measuring first is to find which of the four is actually your problem. Adding a prune for all of them is more disruptive than necessary, and pruning caches that are doing their job makes every build slower.
The prune that is almost always right
docker builder prune -f --filter 'until=168h'
docker image prune -a -f --filter 'until=336h'Build cache older than a week and images unused for a fortnight are safe on a build machine by definition, because anything still needed would have been touched. Running that on a schedule solves the largest category without touching caches that speed up builds.
Workspaces from branches that no longer exist
A workspace directory per branch, kept after the branch is deleted, is the same orphan problem as Bazel output bases. Sorting by modification date finds them:
find ~/actions-runner/_work -maxdepth 2 -type d -mtime +30 \
-exec du -sh {} + 2>/dev/null | sort -h | tail -20The setting that prevents most of it
Artefact and log retention is usually configured on the server rather than the runner, and lowering it from the default frees space on every machine at once. That is worth doing before writing any cleanup script, since it removes the cause rather than the symptom.
Common questions
Why does a self hosted CI runner fill up so fast?
Because it keeps a workspace per job, restores dependency caches for every build, pulls container images, and stores artefacts. All four accumulate and none are cleaned by default.
What should I prune on a build machine?
Docker build cache older than a week and images unused for a fortnight are almost always safe. Workspaces for branches that no longer exist are the next largest and are found by modification date.
How do I avoid pruning caches that speed up builds?
Measure first to find which category is actually growing, and use age filters rather than clearing everything. Dependency caches that are being restored regularly are doing their job.
Is it safe to run cleanup while builds are running?
No. Removing a layer or workspace mid job causes failures that look like flaky tests. Schedule cleanup for a quiet window or gate it on the runner being idle.