Self-hosted runners accumulate workspace leftovers, tool caches, and Docker layers until the disk chokes. Clean the three known hoarders and add a guard.
_work/<repo> retains every checkout and build artifact; a few months of CI can fill tens of GB.
Runners that build images accumulate dangling layers and dangling build cache.
Every version of node/python/go ever installed stays cached in /opt or ~/_work/_tool.
sudo du -xh /var/lib/actions_runner 2>/dev/null | sort -rh | head -10
cd /var/lib/actions_runner && ./config.sh remove --token ... # or prune _work manually between jobs
docker system prune -af --volumes
# weekly cron: ./run.sh once; then prune older tool dirs
Keep runners ephemeral where you can: the cleanest fix is provisioning short-lived runners (autoscaling or containers) so disk pressure never accumulates. A pet runner needs a cage-cleaning schedule.
14GB usable minus your tooling: language toolchains, Docker images, and build artifacts accumulate within one job. Docker especially (image layers from matrix builds) — dmesg-style cleanup between steps keeps a job alive mid-run.
Prune Docker between steps (docker system prune -af), clean build artifacts before the end, use slim base images, and for monorepos, path-filter jobs so only affected parts build. Large per-run cache downloads are also a common silent eater.
Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.
Browse the template store →One-time. Yours to modify. Instant download from the NinjaOps template store.