Docker: No Space Left on Device — Reclaim Disk Safely


A build or pull dies partway through:

write /var/lib/docker/tmp/...: no space left on device

Docker accumulates. Every image layer you have ever pulled, every stopped container, every dangling build-cache entry stays on disk until something removes it. On a busy build host it is routine to find tens of gigabytes of material nothing references. The trick is clearing it without deleting a volume that holds a database.

Key Takeaways

  • Docker never reclaims disk automatically — images, containers, volumes, and build cache accumulate indefinitely.
  • Run docker system df first to see which category is actually consuming space before pruning anything.
  • docker system prune is safe by default; adding –volumes can permanently delete database data.
  • Build cache is often the single largest consumer on CI and development machines.
  • A dedicated filesystem or log rotation prevents Docker from filling the root partition again.

Quick Fix

Check which Docker resource type is consuming your disk before removing anything. The breakdown usually shows build cache or dangling images as the culprit, which are safe to clear without touching your data.

docker system df

Step 1: Confirm It Is Actually Docker

Check overall disk usage first — the full filesystem may have nothing to do with Docker:

df -h /var/lib/docker

If Use% is at or near 100%, look at how Docker is spending it:

docker system df

You get a table of Images, Containers, Local Volumes, and Build Cache, each with a total size and a RECLAIMABLE column. That last column is the important one — it tells you how much you can recover without touching anything in use.

For detail on which specific items are large:

docker system df -v

One more possibility worth ruling out early: you can exhaust inodes while disk space remains. If df -h looks fine but writes still fail, check:

df -i /var/lib/docker

Step 2: Clear the Safe Things First

Start with the operation that cannot destroy data:

docker system prune

This removes stopped containers, unused networks, dangling images, and dangling build cache. It prompts before acting, and it leaves named volumes and tagged images alone. On most machines this alone recovers the majority of the space.

If the report showed build cache as the biggest consumer — common on CI runners and development laptops — target it directly:

docker builder prune

To clear only cache older than a week, keeping recent layers so your next build stays fast:

docker builder prune --filter until=168h

Step 3: Unused Images

Dangling images are untagged leftovers from rebuilds. Remove them alone:

docker image prune

To remove every image not currently used by a container, including tagged ones:

docker image prune -a

That second command deletes images you will have to pull again. On a machine with slow bandwidth or images built locally and never pushed to a registry, that can be expensive. Check what would go first:

docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | sort -k3 -h

To clear images older than a month while keeping recent ones:

docker image prune -a --filter "until=720h"

Step 4: Volumes — Handle With Care

This is where people lose data. Named volumes hold databases, uploads, and anything else meant to outlive a container. Pruning them is irreversible.

List what exists and which are unreferenced:

docker volume ls -f dangling=true

Before deleting any of them, inspect what a volume contains:

docker run --rm -v SOME_VOLUME:/data alpine ls -la /data

A volume shows as dangling simply because no container currently references it — which is exactly what a stopped database’s volume looks like between deployments. Only after confirming a volume is genuinely disposable should you remove it by name:

docker volume rm SOME_VOLUME

Avoid docker system prune --volumes and docker volume prune on any machine holding real data. These delete every unreferenced volume at once, with no way back. The convenience is not worth the risk.

Step 5: Container Logs

A long-running container with a chatty application can produce a log file many gigabytes in size. Docker does not rotate these by default. Find the offenders:

sudo du -sh /var/lib/docker/containers/* | sort -h | tail -5

Fix it globally by configuring rotation in /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": { "max-size": "10m", "max-file": "3" }
}

Validate the file before restarting, since a malformed daemon.json stops Docker from starting at all:

sudo python3 -m json.tool /etc/docker/daemon.json
sudo systemctl restart docker

Note this applies to newly created containers, not existing ones. Recreate long-running containers for the setting to take effect on them.

Verify the Fix

docker system df
df -h /var/lib/docker

Then prove the original operation works rather than assuming:

docker pull alpine:latest

If pulls succeed but builds still fail, the build cache is on a different filesystem — check docker info | grep "Docker Root Dir" to see where Docker actually stores data, which is not always /var/lib/docker.

Prevent It From Recurring

Add log rotation as above — it is the single highest-value change on any server running long-lived containers.

Schedule a conservative weekly cleanup that never touches volumes:

sudo tee /etc/cron.weekly/docker-prune > /dev/null <<'EOF'
#!/bin/sh
docker container prune -f --filter "until=168h"
docker image prune -f
docker builder prune -f --filter "until=168h"
EOF
sudo chmod +x /etc/cron.weekly/docker-prune

Every command there is scoped and safe: no -a, no --volumes. On build servers, giving /var/lib/docker its own partition means a runaway build fills that filesystem instead of taking the whole host down with it — a full root partition breaks logging, SSH, and package management all at once.

Frequently Asked Questions

Does docker system prune delete my volumes?

Not by default. It removes stopped containers, unused networks, dangling images, and dangling build cache. Volumes are only removed if you add the --volumes flag, which is why that flag should be avoided on machines holding data.

What is the difference between docker image prune and prune -a?

Without -a it removes only dangling (untagged) images. With -a it removes every image not used by a running container, including tagged ones you will need to pull or rebuild again.

Why is /var/lib/docker so large even with few images?

Build cache and container logs are usually responsible. Run docker system df to see the breakdown, and check container log sizes under /var/lib/docker/containers, which Docker does not rotate by default.

Can I move Docker's storage to another disk?

Yes. Stop Docker, set data-root in /etc/docker/daemon.json to the new path, copy the existing directory across with rsync -a, then start Docker. Verify with docker info before deleting the original.

Scroll to Top