docker compose down stops and removes your entire Docker Compose stack — containers, networks, and optionally volumes and images. It sounds simple, but picking the wrong flags can mean data loss or leaving gigabytes of stale images on your server.

This guide covers every flag, real-world patterns, and the exact difference between down, stop, and rm.

What docker compose down Actually Does

When you run docker compose down, Docker Compose executes a four-step sequence:

  1. Sends SIGTERM to all running containers in the stack
  2. Waits for them to exit gracefully (default: 10 seconds)
  3. Sends SIGKILL to any container that didn’t stop in time
  4. Removes the stopped containers and the default network

What it does not do by default: delete your named volumes or images. Your database data is safe unless you explicitly tell it otherwise.

docker compose down

Output looks like this:

[+] Running 3/3
 ✔ Container myapp-web-1      Removed    0.4s
 ✔ Container myapp-db-1       Removed    1.2s
 ✔ Network myapp_default      Removed    0.1s

Every Flag Explained

—volumes / -v

Named volumes persist across docker compose down by default. Add -v to delete them:

docker compose down -v

This permanently destroys all data stored in named volumes. That includes your Postgres database, Redis cache, uploaded files — anything stored in a Docker-managed volume.

Use this when:

  • You want to reset a development database to a known state
  • A CI/CD run should be completely isolated from the previous one
  • You’re decommissioning a service and want to clean up

Never run down -v on a production database unless you have a verified backup.

—remove-orphans

When you remove a service from docker-compose.yml but forget to stop the old container, Docker Compose calls it an “orphan” — a container that no longer has a matching service definition.

docker compose down --remove-orphans

Docker Compose warns you about orphans but won’t remove them unless you ask. Add this flag any time you restructure your compose file.

—rmi (Remove images)

Two options here:

# Only remove images that were built locally (not pulled from a registry)
docker compose down --rmi local

# Remove every image used by any service in the compose file
docker compose down --rmi all

Use --rmi all when you want the next docker compose up to pull fresh versions of all images. Useful before a deploy to verify your image tags are correct.

—timeout / -t

Docker waits 10 seconds for a graceful shutdown before force-killing. If your app needs longer to drain connections:

docker compose down -t 30

Applications that handle long-running HTTP requests, database transactions, or message queue consumers typically need more than 10 seconds to shut down cleanly.

—dry-run

New in recent Docker Compose versions — preview what would be removed without actually doing it:

docker compose down --dry-run

Use this before running a destructive down command to confirm you’re targeting the right stack.

docker compose down vs stop vs rm

These three commands are frequently confused:

CommandStopsRemoves containersRemoves networksRemoves volumes
stop
rm✅ (only stopped)optional
downoptional (-v)

Use stop when you want to pause the stack temporarily. The containers still exist; you can inspect them, check logs, and restart with docker compose start.

Use down for a clean teardown. It’s the mirror image of up.

Use rm when you’ve already stopped containers and want to remove them without touching networks.

Combining Flags for Different Scenarios

Development: complete environment reset

docker compose down -v --remove-orphans

Removes containers, networks, and all data volumes. Your next up starts with a fresh database.

CI/CD: maximum isolation

docker compose -f docker-compose.test.yml down -v --rmi local --remove-orphans

Removes everything created during the test run, including locally built images.

Production maintenance: clean restart, preserve data

docker compose down --remove-orphans -t 60

Removes containers and networks, keeps volumes, gives services 60 seconds to shut down gracefully.

Full cleanup: remove everything including pulled images

docker compose down -v --rmi all --remove-orphans

Use with caution — this forces full image re-downloads on the next up.

Working with Multiple Compose Files

If you’re using environment-specific compose files:

# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml down

# Staging
docker compose -f docker-compose.yml -f docker-compose.staging.yml down -v

The -f flag must come before the subcommand.

Removing a Single Service Without Down

docker compose down operates on the entire stack. To remove one container without touching the others:

# Stop and remove a specific service
docker compose rm -sf web

The -s flag stops it first, -f skips the confirmation prompt.

Or to stop a service and remove it cleanly:

docker compose stop web
docker compose rm web

Bind Mounts vs Named Volumes

Understanding this distinction prevents data loss:

services:
  web:
    volumes:
      - ./src:/app/src                    # bind mount — always safe, never deleted
      - node_modules:/app/node_modules    # named volume — deleted by down -v
  db:
    volumes:
      - postgres_data:/var/lib/postgresql/data  # named volume — deleted by down -v

volumes:
  node_modules:
  postgres_data:

docker compose down -v only deletes named volumes (those declared under the top-level volumes: key). Bind mounts — paths starting with ./ or / — are never touched.

Verifying What Will Be Deleted

Before running a destructive down, inspect your volumes:

# List volumes in the current stack
docker compose config --volumes

# Inspect a specific volume
docker volume inspect myapp_postgres_data

# Check volume size
docker system df -v

To back up a Postgres database before wiping:

docker compose exec db pg_dump -U postgres mydb > backup_$(date +%Y%m%d).sql
docker compose down -v

Troubleshooting: Containers Won’t Stop

If containers ignore SIGTERM and timeout hits:

Option 1 — Increase the timeout:

docker compose down -t 60

Option 2 — Fix signal handling in your Dockerfile:

# Use exec form (correct — PID 1 receives signals)
CMD ["node", "server.js"]

# Shell form (wrong — shell catches signals, not your app)
CMD node server.js

Option 3 — Specify the correct stop signal:

STOPSIGNAL SIGUSR2

Some frameworks (like Node.js with pm2, or certain Java apps) respond to different signals.

Automating Cleanup in Scripts

For automated maintenance scripts:

#!/bin/bash
set -e

echo "Backing up database..."
docker compose exec -T db pg_dump -U postgres mydb > /opt/backups/db_$(date +%Y%m%d_%H%M%S).sql

echo "Stopping stack..."
docker compose down --remove-orphans

echo "Pruning unused images..."
docker image prune -f

echo "Done."

Running Docker on a VPS

All these examples assume a Linux server running Docker. If you need a VPS to host your Docker Compose stack, Hetzner Cloud offers the best price-to-performance ratio in Europe — a CX22 server (2 vCPU / 4 GB RAM) costs €4.15/month and handles most Docker workloads comfortably. New accounts get €20 in free credits.

For US-based infrastructure, DigitalOcean provides 1-click Docker Droplets starting at $6/month with $200 in free credits for new accounts. Vultr is another solid option with global data centers and $100 in free credits.

Quick Reference

GoalCommand
Stop stack, keep datadocker compose down
Stop stack + delete volumesdocker compose down -v
Remove orphan containers toodocker compose down --remove-orphans
Force fresh image pullsdocker compose down --rmi all
Full resetdocker compose down -v --rmi all --remove-orphans
Custom timeoutdocker compose down -t 30
Use a specific compose filedocker compose -f file.yml down

Summary

docker compose down is safe by default — it removes containers and networks but never touches your data volumes. Add -v only when you intentionally want to wipe data. In daily development workflows, plain docker compose down followed by docker compose up -d is all you need. Save the -v --rmi all combination for CI pipelines and full resets.

The most important habit: always check docker compose config --volumes before running down -v so you know exactly what data you’re about to delete.