Build cache grows with every changed layer, and on a CI host it can outgrow the images themselves. docker buildx du measures it and docker buildx prune deletes it, both for one builder at a time:
docker buildx du --builder l3-builder | tail -2
docker buildx prune --builder l3-builder -f --max-used-space 20MB | tail -1
docker buildx inspect l3-builder | grep -A3 'GC Policy'
docker buildx inspect default | grep -A4 'GC Policy rule#0'Reclaimable: 42.77MB Total: 42.77MB Total: 94.21kB GC Policy rule#0: All: false Keep Duration: 72h0m0s Max Used Space: 4GiB GC Policy rule#0: All: false Filters: type==source.local type==exec.cachemount type==source.git.checkout Keep Duration: 48h0m0s Max Used Space: 13GiB
--max-used-space trims least recently used records toward a limit, but it freed only 94 kB here: the remaining 42.7 MB is the builder's copy of the docker/dockerfile:1 frontend image, an internal record that prune keeps unless given --all. --filter until=24h prunes by age instead. Automatic garbage collection follows the builder's policy: the private builder's single rule from buildkitd.toml, or the default builder's four built-in rules, which expire cache mounts and build contexts after 48 hours, anything unused for 60 days, and then anything beyond limits derived from the disk size. /etc/docker/daemon.json (daemon.json) sets a fixed limit: "builder": {"gc": {"enabled": true, "defaultKeepStorage": "20GB"}}. On a shared machine prune only your own builder: docker builder prune and docker system prune empty everyone's cache.