Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild

Docker: Remove All Containers Without Removing What You Needed

Sean

Platform Writer

Aug 10, 2026
7 min read

To remove every Docker container, stopped or running: docker rm -f $(docker ps -aq). To remove only the stopped ones, docker container prune is safer and requires no subshell. The important distinction is that neither touches images or volumes — and it is a volume that usually holds the data you did not mean to lose.

Docker: Remove All Containers Without Removing What You Needed

Docker cleanup commands get copied from Stack Overflow without much attention to what each one removes, which is fine until the day the command includes -v or --volumes and the local database goes with it. Here is what each does, ordered from safest to most destructive.

Table of contents

Removing containers

# Every container, running or not, forcibly
docker rm -f $(docker ps -aq)

# Only stopped containers -- the safe default
docker container prune

# Same thing without the confirmation prompt
docker container prune -f

# Stop everything first, then remove -- more graceful
docker stop $(docker ps -q)
docker rm $(docker ps -aq)

docker ps -aq lists the IDs of all containers; -q gives IDs only and -a includes stopped ones. If there are no containers, the subshell is empty and docker rm errors — harmless, but noisy in a script:

# Handles the empty case cleanly
docker ps -aq | xargs -r docker rm -f

docker rm -f sends SIGKILL immediately. For a database or anything holding state, prefer docker stop first, which sends SIGTERM and allows a graceful shutdown before killing after the timeout.

Filtering, so you keep what matters

Removing everything is rarely what you want on a machine running more than one project. Filters make it surgical.

# Only exited containers
docker rm $(docker ps -aq --filter status=exited)

# Only those that exited non-zero
docker rm $(docker ps -aq --filter 'exited=1')

# By name pattern
docker rm -f $(docker ps -aq --filter 'name=test-')

# By label -- the cleanest approach if you set labels
docker rm -f $(docker ps -aq --filter 'label=env=ci')

# Created more than 24 hours ago
docker container prune --filter 'until=24h'

Label your containers and this becomes trivial. A --label env=ci on everything a pipeline creates means cleanup is one filtered command that cannot touch anything else on the host.

For Compose projects, work at the project level rather than the container level:

docker compose down              # containers and networks
docker compose down --volumes    # also named volumes -- destroys data
docker compose down --rmi all    # also images built by this project

What prune actually removes

The prune commands each cover one resource type, and system prune is the one whose behaviour surprises people.

  • docker container prune — stopped containers only. Safe.
  • docker image prune — dangling images (untagged layers). Safe. With -a, every image not used by a container, which means re-pulling.
  • docker network prune — networks with no containers attached. Safe.
  • docker volume prune — volumes not used by any container. This deletes data.
  • docker system prune — containers, networks, dangling images, and build cache. Does not touch volumes by default.
  • docker system prune -a --volumes — everything, including named volumes. This is the one that loses databases.
# See what is actually using space before deleting anything
docker system df
docker system df -v      # per-image, per-container, per-volume detail

Run docker system df first, always. It frequently shows the space is in build cache rather than containers, and docker builder prune reclaims that without touching anything you are using.

A caveat on volume prune: it removes volumes not attached to any container. If you removed a container intending to recreate it, its volume is now unattached and prune will take it.

The volume mistake, spelled out

This is the one worth being explicit about, because the recovery is there is no recovery.

# Removes the container. Volume survives. Data safe.
docker rm -f postgres-dev

# Removes the container AND its anonymous volumes. Data gone.
docker rm -fv postgres-dev

# Removes every unattached volume. Data gone.
docker volume prune

# The full sweep. Everything gone.
docker system prune -a --volumes

Named volumes are not removed by docker rm -v — only anonymous ones. But they are removed by docker volume prune once no container references them, which is the gap people fall through: remove the container on Monday, prune on Tuesday, discover on Wednesday.

# What exists, and what is attached to what
docker volume ls
docker volume inspect postgres-data
docker ps -a --filter volume=postgres-data

# Back up a volume before any cleanup
docker run --rm \
  -v postgres-data:/data:ro \
  -v "$PWD:/backup" \
  alpine tar czf /backup/postgres-data.tar.gz -C /data .

That backup pattern — a throwaway container mounting the volume read-only and a host directory for output — is the standard way to get data out of a volume, and it is worth keeping to hand.

Reclaiming disk space in the right order

The usual reason for all of this is a full disk. Work from safest to most destructive and stop when you have enough.

# 1. What is using the space?
docker system df -v

# 2. Build cache -- usually the biggest and always safe
docker builder prune -f

# 3. Stopped containers
docker container prune -f

# 4. Dangling images
docker image prune -f

# 5. Unused networks
docker network prune -f

# 6. Unused images entirely -- costs a re-pull
docker image prune -a -f

# 7. Volumes. Check what they are first.
docker volume ls
docker volume prune

Build cache is the most common answer and almost nobody checks it first. A machine running CI can accumulate tens of gigabytes there, and docker builder prune is entirely safe — the worst outcome is a slower next build.

Log files are the other quiet consumer. Without a limit, container logs grow without bound:

// /etc/docker/daemon.json -- cap logs and restart the daemon
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Not needing to do this at all

Container cleanup is maintenance work on a machine you manage. It is a real cost — the disk fills at an inconvenient hour, someone runs the wrong prune, and a local database goes with it.

On a managed platform, the container lifecycle is not your concern: you push a repository, get a build log and a live route, and old deploys are retained for rollback rather than accumulating on a disk you have to sweep. RunxBuild deploys Docker services this way — the Docker services documentation covers the build and run stages.

For local development the cleanup habits still apply, and two make the biggest difference:

  • --rm on throwaway containers, so they remove themselves on exit and never accumulate.
  • Named volumes for anything you care about, with an explicit backup routine — never rely on an anonymous volume surviving your next cleanup.
# Self-cleaning: nothing left behind
docker run --rm -it alpine sh

# Named volume, backed up deliberately
docker run -d --name pg -v pg-data:/var/lib/postgresql/data postgres:16

How this fits the rest of the stack

docker rm -f $(docker ps -aq) removes every container and leaves images and volumes intact. Run docker system df before reaching for prune, clear the build cache first because it is usually the bulk of it, and treat anything with --volumes as a data-deletion command rather than a cleanup one. If you would rather not manage container lifecycle on a host at all, the RunxBuild hosting calculator shows what the equivalent services cost by line item.

Useful related references:

FAQ

How do I remove all Docker containers at once?

Run docker rm -f $(docker ps -aq) to remove every container including running ones. For stopped containers only, docker container prune is safer and needs no subshell.

Does removing containers delete my data?

Not by itself. Named volumes survive container removal. Data is lost when you use docker rm -v on anonymous volumes, run docker volume prune, or add —volumes to docker system prune.

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

The plain form removes stopped containers, unused networks, dangling images, and build cache. Adding -a also removes every image not currently used by a container, which means re-pulling them next time.

Why is Docker using so much disk space?

Most often build cache. Run docker system df -v to see the breakdown, then docker builder prune, which is completely safe — the only cost is a slower next build. Unbounded container logs are the other common cause.

How do I remove containers for one project only?

Filter by label or name: docker rm -f $(docker ps -aq —filter ‘label=env=ci’). For Compose projects, docker compose down removes only that project’s containers and networks.

#docker remove all containers#docker prune#docker volumes#docker cleanup#disk space