Stage 1 · Foundations · Chapter 7 of 20 · 5 min read

Volumes and data

Containers are disposable; your data is not. Volumes and bind mounts keep files outside the container, so they survive removal, upgrades and rebuilds.

? What do the diagram colours mean

key idea / Docker itselfcontainer / good pathhost / watch outproblem / blockedneutral

Where data can live

A container’s own files live in its writable layer (chapter 2). That layer is deleted with the container. To keep data, mount storage that lives outside it.

Where a container can keep dataA container has a writable layer that is deleted with it. A named volume is storage managed by Docker, a bind mount is a folder on the host that you choose, and tmpfs is memory that disappears when the container stops.Container dbWritable layergone on docker rm/var/lib/postgresql/data/app/srcmount point/tmp/cachemount pointpgdatanamed volume./srcbind mounttmpfsRAM onlyThe volume and the bind mount outlive the container.tmpfs does not: use it for scratch data that must never touch disk.
The mount point is a path inside the container. What sits behind it decides whether the data survives.
Named volumeBind mounttmpfs
Flag-v pgdata:/data-v "$PWD/src:/app/src"--tmpfs /tmp/cache
Lives inDocker’s storage areaany host path you choosememory
Survives docker rmyesyes, it is your folderno
Use it fordatabases and app statesource code while developing, config filessecrets and scratch files that must not hit disk

The rule of thumb: volumes for data Docker should own, bind mounts for files you want to edit. A bind mount depends on the host’s folder layout; a named volume works the same on every machine.

Data that outlives the container

A volume outlives its containerContainer v1 writes to the pgdata volume. The container is removed. Container v2 mounts the same volume and finds the data.db v1writes rowsvolume pgdatarows on diskdocker rm dbcontainer gonevolume pgdatastill theredb v2reads the rows
This is how you upgrade a database image without losing the database.

-v and --mount

Both flags do the same job. -v is short; --mount spells every part out and fails loudly on a typo instead of silently creating an empty volume.

$ docker run -d --name db -v pgdata:/var/lib/postgresql/data postgres:16
$ docker run -d --name db --mount type=volume,src=pgdata,dst=/var/lib/postgresql/data postgres:16

$ docker run -d -v "$PWD/nginx.conf:/etc/nginx/nginx.conf:ro" nginx:1.27   # :ro = read-only

If the first part of -v starts with / or ./ it is a bind mount; otherwise it is a volume name. -v data:/x and -v ./data:/x are very different things.

Managing volumes

CommandDoes
docker volume lslists volumes
docker volume inspect pgdatashows where it lives and when it was created
docker volume rm pgdatadeletes it, and its data, for good
docker volume prunedeletes every volume no container uses. Read the list first.

To back a volume up, mount it next to a host folder in a throwaway container and tar it:

$ docker run --rm -v pgdata:/data:ro -v "$PWD:/backup" alpine:3.20 tar czf /backup/pgdata.tgz -C /data .

Try it yourself

  1. Step 1 · Write into a named volume

    docker run creates notes the first time it is used.

    $ docker run --rm -v notes:/data alpine:3.20 sh -c 'echo first note > /data/today.txt'
    $ docker volume ls
    DRIVER    VOLUME NAME
    local     notes
  2. Step 2 · A brand-new container sees the same file

    The first container is already gone (--rm). The data was never in it.

    $ docker run --rm -v notes:/data alpine:3.20 cat /data/today.txt
    first note
  3. Step 3 · Without a volume, the file dies with the container
    $ docker run --name temp alpine:3.20 sh -c 'echo lost > /today.txt'
    $ docker rm temp
    $ docker run --rm alpine:3.20 cat /today.txt
    cat: can't open '/today.txt': No such file or directory
  4. Step 4 · A bind mount shows host edits live

    Change the file on the host; the container sees it immediately, with no rebuild.

    $ mkdir site && echo '<h1>v1</h1>' > site/index.html
    $ docker run -d --name web --rm -p 8080:80 -v "$PWD/site:/usr/share/nginx/html:ro" nginx:1.27
    $ curl -s localhost:8080
    <h1>v1</h1>
    $ echo '<h1>v2</h1>' > site/index.html
    $ curl -s localhost:8080
    <h1>v2</h1>
    $ docker stop web
  5. Step 5 · Clean up
    $ docker volume rm notes
    notes
Common mistakeBind-mounting your project over /app, which hides the node_modules the image installed. A mount covers everything at that path. Mount only the source folder, or add an anonymous volume for /app/node_modules.

Recap

Quick check

You upgrade Postgres with docker rm db and a new container from a newer image. When is the data still there?

Show answer

Answer: Only if the data directory was on a volume or bind mount.

The writable layer is deleted with the container. Data in a named volume or bind mount survives and can be mounted by the new container.

You want to edit code on your laptop and see the change in the container immediately. Which mount?

Show answer

Answer: A bind mount of your source folder.

A bind mount maps your host folder into the container, so both see the same files.

Docker volumes: common questions

What is the difference between a Docker volume and a bind mount?

A named volume is storage that Docker manages and is the same on every machine. A bind mount maps a host folder you choose into the container, which suits code and config you edit.

Does docker rm delete volumes?

No. docker rm deletes the container and its writable layer. Named volumes stay until you run docker volume rm, docker volume prune or docker compose down -v.