Quick answer
Check what is using space first with docker system df, then use the narrowest command that solves your problem.
docker system df # what is using disk space
docker container prune # remove all STOPPED containers
docker rm -f $(docker ps -aq) # remove ALL containers, including running ones
docker image prune -a # remove all images not used by a container
docker system prune -a --volumes # nuclear option: see the warnings belowRemove all containers
docker ps lists running containers; add -a to include stopped ones and -q to print only their IDs. Feeding those IDs to docker rm is the classic way to delete every container. docker rm refuses to remove a running container, so either stop everything first or add -f, which sends SIGKILL and removes the container in one step. Stopping first gives processes the chance to shut down cleanly (Docker sends SIGTERM and waits 10 seconds by default), which is kinder to databases.
Removing a container deletes its writable layer: any files it wrote outside of a volume or bind mount are gone. Data in named volumes and bind-mounted host folders survives.
Remove stopped containers only
docker container prune deletes every container that is not running and asks for confirmation; -f skips the prompt. Filters let you keep recent ones, for example only removing containers stopped more than a day ago.
docker container prune
docker container prune -f --filter "until=24h"
# Equivalent with explicit IDs
docker rm $(docker ps -aq --filter status=exited)Stop and remove running containers
# Graceful: stop everything, then remove everything
docker stop $(docker ps -q)
docker rm $(docker ps -aq)
# Forceful: kill and remove in one go
docker rm -f $(docker ps -aq)
# Same thing without an error when there are no containers (GNU/BSD xargs)
docker ps -aq | xargs -r docker rm -fNote
If there are no containers, docker rm $(docker ps -aq) prints "requires at least 1 argument". It is harmless; the xargs -r form avoids it.
Remove a single container
docker rm my-container # by name or ID (must be stopped)
docker rm -f my-container # stop and remove
docker run --rm alpine echo hi # --rm deletes the container when it exitsRemove containers selectively with filters
Deleting everything is rarely necessary. docker ps accepts --filter (or -f) flags that you can combine with docker rm, so you can target containers from one image, with a name pattern or with a label, and leave the rest running. Always run the docker ps part on its own first to see exactly which containers match.
Labels are the most reliable option for automation. If your test scripts start containers with --label env=test, cleaning up afterwards is one command that cannot touch anything else.
docker ps -a --filter ancestor=postgres:16 # created from an image
docker ps -a --filter name=api # name contains "api"
docker ps -a --filter label=env=test # by label
docker ps -a --filter status=exited --filter status=created
docker rm -f $(docker ps -aq --filter label=env=test)Remove Docker images
Images take far more space than containers. There are three levels. Dangling images are untagged layers left behind when you rebuild an image with the same tag; they show as <none>:<none> and are always safe to delete with docker image prune. Unused images are tagged images that no container (running or stopped) references; docker image prune -a removes them, which means the next docker run or build has to pull or rebuild them. Finally, docker rmi removes specific images, and with all image IDs it removes everything it can.
Docker will not remove an image that a container uses. Remove the containers first, or use -f, which untags the image but may still leave layers in use.
docker images # list images
docker images -f dangling=true # list dangling images
docker image prune # delete dangling images
docker image prune -a # delete all images without a container
docker image prune -a --filter "until=168h" # ...older than 7 days
docker rmi nginx:1.27 # remove one image (alias: docker image rm)
docker rmi $(docker images -q) # try to remove every image
docker rmi -f $(docker images -q) # force itVolumes, networks and build cache
Volumes hold persistent data such as Postgres or MySQL data directories, so treat them with care. Since Docker Engine 23, docker volume prune removes only unused anonymous volumes by default; add -a to also remove unused named volumes, which is where most real data lives. Unused custom networks are removed with docker network prune, and the BuildKit cache, which can grow to many gigabytes on build machines, with docker builder prune.
docker volume ls
docker volume prune # unused anonymous volumes
docker volume prune -a # unused anonymous AND named volumes
docker volume rm pgdata # one specific volume
docker network prune
docker builder prune # dangling build cache
docker builder prune -a # all build cacheWarning
Deleting a volume is permanent. There is no recycle bin. If a volume holds a database, back it up first, for example with docker run --rm -v pgdata:/data -v "$PWD":/backup alpine tar czf /backup/pgdata.tgz -C /data .
docker system prune: clean everything at once
docker system prune combines the prune commands. Without flags it removes stopped containers, unused networks, dangling images and dangling build cache, which is safe for almost any machine. -a widens it to every image not used by a container and all build cache. --volumes additionally removes unused anonymous volumes (on Docker 23 and later; named volumes still need docker volume prune -a). Add -f to skip the confirmation prompt in scripts.
Use the plain version regularly on a laptop. Use -a when you are short on disk and do not mind re-pulling images. Think twice before adding --volumes on any machine that runs stateful services, and never run it on a production host while a database container is temporarily stopped: a stopped container's volumes count as unused.
docker system prune # safe default
docker system prune -a # + all unused images and build cache
docker system prune -a --volumes # + unused anonymous volumes
docker system prune -af --filter "until=72h"Docker Compose: down, -v and --rmi
For a Compose project, docker compose down is the right tool: it stops and removes the project's containers and the networks Compose created, leaving everything else on the machine alone. -v (--volumes) also removes the named volumes declared in the file's top-level volumes: section and anonymous volumes attached to the containers, which resets databases to empty. --rmi local removes images built by the project without a custom tag, --rmi all removes every image the services use, and --remove-orphans cleans up containers from services you deleted from the file.
Note that docker compose stop only stops containers; it does not remove anything.
docker compose down # containers + networks
docker compose down -v # + volumes (deletes data!)
docker compose down --rmi all --remove-orphans
docker compose -p myproject down # target a project by nameReclaim disk space and automate clean-up
After pruning, run docker system df again to confirm the space came back; docker system df -v breaks usage down per image, container and volume. On macOS and Windows, Docker Desktop stores everything inside a virtual disk. Pruning frees space inside that disk, and recent versions return it to the host automatically, but if your host disk does not recover, lower the disk size limit in Settings, Resources, or use the Clean / Purge data option.
On CI runners and build servers, disk usage grows every day. A scheduled job that runs a filtered prune keeps it under control without touching anything recent. A nightly docker system prune -af --filter "until=72h" removes stopped containers and unused images older than three days while leaving volumes alone. Schedule it with cron (see our guide on running a cron job every 5 minutes and the cron expression generator) or a systemd timer.
docker system df -v
# crontab entry: every night at 03:15, prune anything unused for 3+ days
15 3 * * * /usr/bin/docker system prune -af --filter "until=72h" >> /var/log/docker-prune.log 2>&1Windows PowerShell and cmd equivalents
The prune commands are identical on every platform. The $(...) substitution also works in PowerShell, because PowerShell's subexpression returns an array that is passed as separate arguments. In the classic Command Prompt, use a for /f loop instead. Docker Desktop also has a GUI route: Troubleshoot, then Clean / Purge data, which resets everything including volumes.
# PowerShell
docker rm -f $(docker ps -aq)
docker ps -aq | ForEach-Object { docker rm -f $_ }
docker rmi -f $(docker images -q)
docker system prune -a:: Command Prompt (use %%i inside a .bat file)
for /f "tokens=*" %i in ('docker ps -aq') do docker rm -f %i
for /f "tokens=*" %i in ('docker images -q') do docker rmi -f %iRemove all Docker containers: FAQ
Quick answers to common questions
How do I delete all Docker containers at once?
Run docker rm -f $(docker ps -aq). docker ps -aq lists the IDs of all containers and -f stops running ones before removing them. Use docker container prune if you only want to remove stopped containers.
Does docker system prune delete volumes?
Not by default. docker system prune --volumes removes unused anonymous volumes; on Docker 23 and later named volumes are kept unless you run docker volume prune -a.
What is a dangling image in Docker?
An image layer with no tag, shown as <none>:<none>, usually left behind when you rebuild an image under the same tag. docker image prune removes dangling images safely.
Does docker compose down delete my data?
No. docker compose down removes containers and networks only. Adding -v also removes the project's volumes, which deletes database data stored in them.
Why can't I remove a Docker image?
A container, even a stopped one, still references it. Remove the container with docker rm first, or force-remove the image with docker rmi -f.

