What you're seeing
$ docker pull nginx
docker: write /var/lib/docker/tmp/...: no space left on device.Variants:
Error response from daemon: write ...: no space left on device— most common, hits during pull/build/runError processing tar file: write ...: no space left on device— during image extractionfailed to register layer: write ...: no space left on device— same thing, different stepError response from daemon: failed to create endpoint X on network bridge: ... no space left on device— usually inode exhaustion, not space
What's causing this error
Docker stores everything under /var/lib/docker (or ~/Library/Containers/com.docker.docker/Data on macOS / a WSL2 VHD on Windows). That directory grows by:
- Stopped containers. Each one keeps its writable layer on disk until explicitly removed.
docker rmit, the space comes back. - Unused images. Pulling 5 versions of
node? All five sit on disk forever unless you delete them. - Build cache. BuildKit caches every intermediate layer of every build. On dev machines this turns into 20+ GB silently.
- Orphan volumes.
docker rmremoves a container but leaves its named/anonymous volumes by default. Years of orphaned volumes = real space. - Container logs. Docker's default JSON log driver doesn't rotate. A noisy container can write hundreds of GB of logs.
Less common but worth knowing:
- Inode exhaustion. The disk has space but no free inodes — happens on small filesystems with many tiny files.
df -iconfirms. - Docker Desktop disk-image limit (macOS/Windows). The VM has a fixed virtual disk size; you may have actual disk space free but Docker's VM doesn't.
How to fix it
Step 1: See what's actually full
df -h
docker system dfThe first shows whether your filesystem is actually full or just Docker's chunk. The second shows what inside Docker is taking space:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 47 12 18.2GB 12.4GB (68%)
Containers 23 4 342MB 298MB (87%)
Local Volumes 31 8 8.1GB 6.2GB (76%)
Build Cache 1023 0 14.7GB 14.7GBThe RECLAIMABLE column is what you can safely delete.
Step 2: Safe cleanup
Start with the conservative option — removes only what's definitely unused:
docker system pruneThis deletes: stopped containers, dangling images (untagged), unused networks. Leaves: running containers, all tagged images, all volumes, build cache.
If that's not enough:
docker system prune -aSame as above plus all unused images (not just dangling — anything no container is using). This is what most people actually need.
Step 3: Aggressive cleanup (when -a isn't enough)
docker system prune -a --volumes
docker builder prune -a--volumesalso removes unused named volumes. Be careful — this is where databases live. Make sure you don't have an unused-looking volume that has data you care about.docker builder prune -aseparately clears the build cache, whichdocker system pruneonly touches partially.
Step 4: Target a specific category
When you want surgical removal instead of a sweep:
# All stopped containers
docker container prune
# Just dangling images (untagged)
docker image prune
# All images not used by any container
docker image prune -a
# All unused volumes (no container referencing them)
docker volume prune
# Just the build cache
docker builder prune
# Older than 24h, more selective
docker builder prune --filter "until=24h"Step 5: Fix it permanently — log rotation
The log file growth catches people by surprise. Edit /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "3"
}
}Then restart docker:
sudo systemctl restart dockerNew containers will rotate logs to a max of 3 × 50MB. Existing containers need to be recreated to pick up the new policy.
Step 6: Docker Desktop disk-image limit (macOS / Windows only)
If df -h shows your disk has space but Docker is full:
- macOS: Docker Desktop → Settings → Resources → Disk image size. Move the slider up.
- Windows (WSL2): same setting, or expand the WSL2 VHD:
wsl --shutdown, then expand thedocker-desktop-dataVHD via PowerShell.
Common edge cases
| Situation | What's actually wrong |
|---|---|
df -h shows plenty of space, Docker says no space | Inode exhaustion. Run df -i to confirm. Cleanup is the same (docker system prune); inodes free as files delete. |
| Pruned everything, still no space | Container logs not pruned by prune. Find with du -sh /var/lib/docker/containers/* and truncate the giant ones, OR recreate the container after setting log rotation. |
| Docker Desktop says full, host disk has space | VM disk-image size cap. Raise it in Settings → Resources → Disk image size. |
| Pruning takes forever | Big build cache or many layers. Let it finish — it's IO-bound, not stuck. |
| Volumes you don't recognise after pruning | You had data in unnamed/anonymous volumes that's now gone. Always use named volumes (docker run -v dbdata:/var/lib/postgresql) so they're identifiable. |
failed to register layer mid-pull | Disk filled during the pull. Free space first, then re-pull (Docker resumes from where it stopped, no full re-download). |