Docker Volume Data Missing After Container Recreation
Quick answer
Data that seems to vanish after recreating a container almost always means the data was never actually stored in a persistent, correctly-referenced volume in...
Data that seems to vanish after recreating a container almost always means the data was never actually stored in a persistent, correctly-referenced volume in the first place — it was likely in an anonymous volume that got orphaned, or the container was pointed at a different volume than the one you expect, rather than Docker genuinely losing previously stored data.
The Problem
You stop, remove, and recreate a container (a common step when updating an image or changing configuration), and data that should have persisted — database contents, uploaded files — is gone:
docker compose down
docker compose up -d
# data that existed before is now missing
Why It Happens
Several distinct volume-related misunderstandings commonly cause this exact symptom:
- The container was using an anonymous volume (declared in the image itself via
VOLUMEin the Dockerfile, or a compose volume mount without a name) — recreating the container withdocker compose downfollowed byup(rather than just restarting) can leave the old anonymous volume orphaned, unless it was explicitly reused, with the new container getting a fresh, empty anonymous volume instead - The volume mount path inside the container changed between the old and new container configuration (even slightly, like a trailing slash difference or a different directory name), causing the application to write to what is technically a different mount point than where the previously persisted data actually lives
docker compose down -vwas used, which explicitly removes named volumes along with the containers — a common and easy mistake if the intent was just to stop and restart, not to also delete persistent data- The application itself is configured to look for its data in a different location than where the volume is actually mounted, so even though data is genuinely being persisted correctly by Docker, the application can't find it after restart due to its own internal configuration pointing elsewhere
The Fix
First, confirm whether the volume in question is named or anonymous, since this fundamentally changes how it behaves across container recreation:
docker volume ls
An anonymous volume shows as a long random hash rather than a meaningful name — if your data was stored in one of these, it's genuinely difficult to reliably reference and reuse across recreations, which is exactly why named volumes are strongly preferred for anything meant to persist.
Convert to an explicitly named volume, which persists reliably across container recreation as long as you don't explicitly remove it:
services:
db:
image: postgres:16
volumes:
- db_data:/var/lib/postgresql/data # named volume, not anonymous
volumes:
db_data:
With this named volume declared, docker compose down followed by up correctly reuses the same db_data volume and its contents, since Docker Compose tracks named volumes by name across separate up/down cycles, unlike anonymous volumes.
Confirm the exact mount path is genuinely consistent between the old and new container configuration — even a subtle difference means the new container writes to (and reads from) an effectively different location, regardless of whether the underlying volume itself still has the old data intact:
# Confirm the exact path matches exactly between configurations
volumes:
- db_data:/var/lib/postgresql/data # must match exactly, including trailing characters
Avoid docker compose down -v unless you specifically intend to delete persistent data — use plain docker compose down (without -v) for a normal stop-and-remove-containers operation that preserves named volumes:
# Preserves named volumes
docker compose down
# Explicitly deletes named volumes too - use deliberately, not as a routine habit
docker compose down -v
If you suspect data might still exist in an orphaned anonymous volume from before, list all volumes (including unnamed ones) and inspect them before concluding the data is genuinely lost:
docker volume ls -f dangling=true
docker run --rm -v <anonymous_volume_name>:/data alpine ls -la /data
This mounts a suspected orphaned anonymous volume into a temporary, disposable container just to inspect its contents, without needing to guess or reconstruct anything — if the old data is genuinely still there, you can then copy it out and into your new, properly named volume going forward.
Still Not Working?
If you've confirmed a named volume is correctly configured and mounted at a consistent path, but data still appears to reset, check whether the application itself is performing its own destructive initialization on startup — some database images or applications run initialization scripts that reset or overwrite data under certain conditions (like detecting what looks like an "empty" or "first-time" state due to a subtle difference in how the volume was mounted or permissioned), which would produce data loss that has nothing to do with Docker's volume persistence itself actually failing.