Docker Out of Disk Space: Cleaning Images, Build Cache, Logs, and Volumes

Troubleshoot Docker's no space left on device error: inspect images, containers, and build cache with docker system df, check logs and mounts, understand prune and compose down, configure log rotation, and verify application data.

When Docker runs out of disk space, start with docker system df -v, then inspect container logs and mounted directories. Prioritize build cache, dangling images, and obsolete containers that you have confirmed can be recreated or discarded. Check volume ownership and backups separately; an “unused” volume is not automatically safe to delete.

After several months of self-hosting, image versions, build cache, logs, and application data can all accumulate. A single prune handles only some of them, and expanding its scope blindly can delete a database.

This guide primarily covers Linux Docker Engine and Compose V2. Docker CLI inspection commands generally also work in Windows PowerShell; host commands marked Bash should run on the Linux machine actually hosting Docker. Documentation was checked on October 22, 2026. No cleanup or container recreation described here has been performed on your server.

If you arrived from deploying Syncthing with Docker or the Joplin Server self-hosting guide, locate those services’ actual data directories before deciding what to clean.

Identify the full disk and the connected host

The Docker CLI may connect to the local machine, a remote SSH context, or Docker Desktop’s Linux VM. Space figures from the wrong context may have nothing to do with the server you are troubleshooting.

1
2
3
4
5
docker context show
docker context ls
docker version
docker info
docker compose version

Check the server information, current context, and Docker data directory. On Linux, the default is often /var/lib/docker, but rootless installations, custom settings, and different storage backends may use other paths. Do not treat this default path as a directory to delete.

On the Linux host, check filesystem capacity and inodes:

1
2
df -h
df -i

Even with free disk capacity, inode exhaustion caused by many small files can trigger no space left on device. If writes target a bind mount on another disk, check that mount point rather than only the system disk.

Docker Desktop adds a virtual disk layer. Space freed inside containers, available virtual disk capacity, and the host disk image’s actual allocation may change at different times. An unchanged Windows C: drive usage figure therefore does not by itself prove that Docker cleanup failed. This guide does not provide a virtual disk compaction command intended to work across all Desktop backends.

Use disk usage details to distinguish five data types

Begin with read-only queries:

1
2
3
4
5
docker system df
docker system df -v
docker ps -a --size
docker image ls
docker volume ls

docker system df reports Docker resource usage; -v expands image, container, and local volume details. Images can share layers, so adding every image’s displayed SIZE does not give actual disk consumption.

Type Typical contents Preferred approach
Images Current and older versions, build artifacts Keep rollback versions; inspect dangling images before pruning
Container writable layer Uploads and temporary files without persistence Determine whether data can be discarded or moved
Build cache Reusable results from Dockerfile steps Prune by age, accepting slower subsequent builds
Volumes and bind mounts Databases, configuration, attachments, models Manage per application; back up before changes
Container logs Standard output and standard error Identify the logging driver and configure rotation

RECLAIMABLE estimates space eligible for resource reclamation; it does not establish whether the application still needs those resources. An older image may be the only usable rollback version, and an unreferenced volume may contain a retired database that must still be retained.

The writable layer size shown by docker ps --size also excludes the total size of mounted data and logs. If that figure is small while host disk usage keeps growing quickly, investigate those two areas next.

Map containers to their data before cleanup

The following examples assume a container named my-app; replace it with the actual name:

1
2
3
docker inspect my-app --format '{{json .Mounts}}'
docker inspect my-app --format '{{json .HostConfig.LogConfig}}'
docker inspect my-app --format '{{.LogPath}}'

In Mounts, focus on:

  • Type: distinguishes volume from bind.
  • Name: the Docker-managed volume name.
  • Source: the source path on the host.
  • Destination: the mount location inside the container.
  • RW: whether the container can write to it.

For example, if /data inside the container maps to /srv/my-app/data on the host, investigate growth at the host and application levels. Deleting old images will not shrink the attachment library there.

If database files are still written into the container’s writable layer, arrange a backup and migration to persistent storage first. Deleting that container could lose the data, so do not proceed to container cleanup yet.

For a Compose project, also run these commands from the correct project directory:

1
2
3
docker compose config --quiet
docker compose ps -a
docker compose images

If you use custom -f, -p, or environment files, use the same parameters for inspection and subsequent operations. Changing the project name may create another set of volumes, making the application appear to have lost its data.

Record actual volume names, Compose files, and image versions. Store backups separately where enough space is available. Use database-supported logical backups or consistent snapshots; archiving a live database directory can produce an unusable backup.

Images and build cache: start with reproducible data

Assess build cache first

If Build Cache accounts for most usage, pruning it is usually more appropriate than touching application volumes. The trade-off is that the next build may download dependencies and compile again, taking longer.

1
docker builder prune --filter 'until=168h'

This prunes eligible build cache according to an age filter and retains interactive confirmation. 168h means seven days, an example retention window to adjust to your build frequency. This is not a preview: confirming it actually deletes cache. See docker builder prune for parameters.

In a Buildx environment with multiple builders, also check the current builder:

1
2
docker buildx ls
docker buildx du

docker buildx du reports cache usage for the currently selected builder. Do not observe high usage on one builder and repeatedly prune another. Check remote build machines separately as well; do not assume they share your local disk.

Decide whether dangling images can be removed

List dangling images:

1
docker image ls --filter dangling=true

After confirming that these build artifacts are no longer needed, run:

1
docker image prune

By default, this removes dangling images. Adding -a broadens the scope to images not referenced by any container, including normally tagged older versions. That affects offline recovery and rollbacks, so it should not be a routine shortcut. See docker image prune for the full rules.

To remove a single confirmed obsolete image, specifying its actual ID makes the scope easier to control:

1
docker image rm IMAGE_ID

If Docker reports a reference conflict, inspect the containers using that image and reconsider whether it must be retained. Do not immediately bypass the message with a force option.

Remove obsolete containers individually by name

A stopped container can still contain valuable files. Inspect its mounts and writable layer before deciding whether to remove it:

1
2
3
docker ps -a --filter status=exited --size
docker inspect old-test-container --format '{{json .Mounts}}'
docker diff old-test-container

docker diff shows container filesystem changes. It is not a backup and does not replace checking mounted directories. Only after confirming that this is a disposable test container should you remove it:

1
docker container rm old-test-container

Neither -f nor -v is used here. Removing the container still discards its writable layer and container logs; export important files first. See docker container rm for removal rules.

Growing logs: address the cause after pruning cache

If docker system df shows little reclaimable space, inspect the logging driver and log path next. Docker’s default json-file driver has no default size limit, so frequent error output can consume disk indefinitely.

1
2
3
4
docker info --format '{{.LoggingDriver}}'
docker inspect my-app --format '{{json .HostConfig.LogConfig}}'
docker inspect my-app --format '{{.LogPath}}'
docker logs --tail 100 my-app

The daemon’s default driver may differ from a container’s actual driver; use the container’s LogConfig as the authority. LogPath may not always provide a directly accessible file path, depending on the driver and environment. See Docker’s logging driver documentation for configuration behavior.

On Linux, you can inspect the size of the returned path without modifying it. Replace the example below with the actual log file path:

1
sudo du -h /actual/path/to/container-json.log

Do not directly delete or truncate Docker-managed log files. The documentation states that the Docker daemon exclusively manages them, and external modification can interfere with logging. If logs repeatedly report database connection failures or permission errors, fix the application issue first; rotation alone still produces unnecessary logs.

Configure log rotation for a Compose service

Merge this logging configuration into the existing service, preserving its image, ports, environment variables, and data mounts:

1
2
3
4
5
6
7
services:
  app:
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

This is a configuration fragment, not a complete standalone Compose file. Replace app with the actual service name. max-size sets the rotation threshold per log file, and max-file sets the number retained; see the json-file documentation for details.

Check syntax after editing. Recreate the target service only when a short interruption is acceptable and its data is persistent and backed up:

1
2
3
docker compose config --quiet
docker compose up -d --no-deps --force-recreate app
docker compose ps

Recreation replaces the container and does not automatically preserve its writable layer. If the service relies on anonymous volumes, determine how to reuse or migrate them before recreating it. Then find the new container’s actual name and inspect it:

1
2
docker inspect my-app --format '{{json .HostConfig.LogConfig}}'
docker logs --tail 100 my-app

Editing configuration and running docker compose restart does not update logging options set when the container was created. If the old configuration remains, check the service name, Compose file, project name, and actual container ID.

Rotation limits local log history; applications requiring long-term audits need separate collection and retention. Logs written by the application into mounted directories also need application settings or their own rotation mechanism; Docker’s stdout rotation does not manage those files.

Volumes: unused does not mean disposable

List volumes without container references to identify candidates for investigation:

1
2
3
docker volume ls --filter dangling=true
docker volume inspect my-project-data
docker ps -a --filter volume=my-project-data

A volume may lack a container reference simply because someone ran docker compose down. After container removal, its database files may still hold all the application data required for the next startup. See Docker Volumes for persistence behavior.

Before taking action, answer four questions:

  1. Which application and environment own this volume?
  2. Has the application been permanently retired, or will it be recreated later?
  3. Is there an independent backup with a verified recovery procedure?
  4. Could this cleanup also delete the backup location?

Consider deleting a specific volume with docker volume rm 实际卷名 only after confirming it is no longer needed; replace the final placeholder with the actual volume name. This guide does not recommend bulk volume pruning as routine maintenance. When growth comes from database records, attachments, or models, use application-supported retention, archiving, or migration first.

The scope of prune and compose down

Different commands have different removal scopes:

Command or option Scope to understand
docker image prune Dangling images by default
docker image prune -a All images without container references
docker system prune Stopped containers, unused networks, dangling images, and unused build cache
docker system prune --volumes Additionally includes unused anonymous volumes; not a backup cleanup mechanism
docker volume prune Currently defaults to unused anonymous local volumes; --all extends to unused named volumes
docker compose down Removes project containers and networks by default without deleting volumes
docker compose down -v Additionally deletes declared named volumes and attached anonymous volumes, except external volumes

Check your installed version’s --help and current official documentation for exact behavior. See system prune, volume prune, and compose down.

Bulk cleanup cannot simply be undone. Cache can be rebuilt and images may be pulled again, but deleted volumes require a valid backup for recovery. Also, Compose retaining anonymous volumes by default does not guarantee that the next up automatically reattaches the original anonymous volume. Use explicit data paths or named volumes for long-running applications, and retain the corresponding configuration.

Verify both reclaimed space and application reads and writes

Recheck usage after each resource type so you can identify what actually freed space:

1
2
3
4
docker system df -v
docker ps -a --size
docker compose ps
docker compose logs --tail 100

On the Linux host, check again:

1
2
df -h
df -i

A container showing Up does not establish recovery. Open the service, read an existing record, write a disposable test record, and confirm that the database or sync directory is using the original data. For services recreated to change logging, monitor disk growth for a while to confirm that rotation is configured and application errors are resolved.

If less space was freed than expected, investigate by symptom:

Symptom What to check next
Large image list, little space freed Shared image layers and layers still referenced by containers
Build Cache unchanged Whether context and builder match the intended target
Small Docker resources, disk still full Bind-mounted directories, logs, and other host files
Linux still reports insufficient space Actual target filesystem, inodes, quotas, and storage backend
More free space inside Desktop, unchanged host usage Platform-specific virtual disk reclamation
Setup page appears after container recreation Changed project name, volume name, bind path, or anonymous volume association

In the last case, stop further writes immediately and check whether the old volume remains and configuration points to a new directory. Do not proceed with volume pruning, which could destroy old data that is still recoverable.

If the service fails after cleanup, restore the Compose configuration, inspect persistent mounts, and recreate it with a retained image version. If a volume was deleted, pulling the image again will not restore application data; follow the previously verified backup recovery procedure.

Plan ongoing maintenance

At minimum, record the Docker context, resource usage, actual data directories, logging driver, and backup location. Development machines with frequent builds can periodically assess cache; servers running databases should prioritize capacity alerts, database backups, and recovery drills.

Do not directly schedule commands combining force options, broad image pruning, and volume cleanup. Collect read-only usage statistics over time first, identify which resources keep growing, and choose the corresponding retention policy.

For moving data to another disk, see rsync incremental transfer and verification. For database directories, stop relevant writes first or use an application-supported consistent backup; a successful file copy does not prove the database backup is recoverable.