What happens to a container's writable-layer data when the container is removed?
Quick Answer
Any data written to a container's own writable layer — files created or modified that aren't stored in a mounted volume or bind mount — is permanently and irrecoverably deleted the moment that container is removed (docker rm), since the writable layer belongs exclusively to that one specific container and has no independent existence beyond it. This is precisely why any data meant to outlive a single container's removal must live in a separate, explicitly mounted volume, not in the container's own filesystem.
Detailed Answer
The demonstration
docker run -d --name my-db postgres:16 # no volume mounted -- data lives ONLY in the writable layer
docker exec my-db psql -U postgres -c "CREATE TABLE important_data (...);"
# ... insert critical data ...
docker rm -f my-db
docker run -d --name my-db postgres:16 # a FRESH container, from the same image
docker exec my-db psql -U postgres -c "SELECT * FROM important_data;"
# ERROR: relation "important_data" does not exist
The second container is entirely new. It starts from the image's original, unmodified layers, with a fresh, empty writable layer. Every change made to the first container (the new table, its data) lived exclusively in that specific container's now-deleted writable layer. That data is gone permanently, with no relationship at all to the second container, even though both were started from the identical image.
Why this is expected, correct behavior — not a bug
Recall from the fundamentals topic: an image is an immutable, read-only template, and each container gets its own independent writable layer on top of it via copy-on-write (see that question). This is precisely what allows many containers to be started from the same image simultaneously, each with fully independent state. But it also means a container's writable layer is fundamentally tied to that one container's lifetime. It is not tied to the image, and it is not shared with any other container.
The fix: mount a volume for anything that needs to survive
docker volume create db-data
docker run -d --name my-db -v db-data:/var/lib/postgresql/data postgres:16
Now the database's actual data files live in the named volume db-data, not in the container's own writable layer. Removing this container and starting a fresh one picks up exactly where the previous container left off, as long as it mounts the same volume. This works since the volume's data is independent of any specific container's lifecycle:
docker rm -f my-db
docker run -d --name my-db -v db-data:/var/lib/postgresql/data postgres:16
docker exec my-db psql -U postgres -c "SELECT * FROM important_data;"
# the data is still there -- it was never IN the removed container's writable layer at all
The mental model this reinforces
Think of the writable layer as entirely disposable, scratch space specific to one container instance, and volumes as the only place genuinely persistent data should live. Any file written outside a mounted volume path should be treated as something you're comfortable losing the instant that specific container is removed. Logs (which should generally go to stdout/stderr and be captured by Docker's logging driver instead; see the lifecycle topic), temporary caches, and anything else genuinely ephemeral are fine to leave in the writable layer. Real application data, database files, and uploaded content are not.
A common real-world mistake this explains
A surprisingly common incident pattern looks like this: a database or application was run without a mounted volume during initial setup, perhaps for a "quick test" that then quietly became the actual production deployment. Months of accumulated data are then permanently lost the first time that one specific container happens to be removed or replaced, whether during a routine update, a host migration, or simple operator error. This happens precisely because nothing was ever actually persisted outside that one container's own writable layer. Verifying that every stateful container mounts an appropriate volume for its real data, rather than just assuming it does, is a basic, essential production readiness check.