LearnAI ToolsCareerPractice BuildsPlayDevelopmentContact
Lesson 814 min read

Volumes and Bind Mounts: Keeping Your Data

Keep data safe when containers are removed: use named volumes for databases and bind mounts to share your own files with a container.

On this page 11 sections

Introduction

Containers are meant to be disposable: you remove them and start new ones whenever you update an image. But databases, uploaded files and logs must survive that. Docker solves this by storing such data outside the container, in volumes or bind mounts.

What You Will Learn
  • Why files written inside a container are lost when it is removed.
  • How named volumes keep data, for example for a database.
  • How bind mounts share a folder from your computer with a container.
  • How to mount read-only, and how to list, inspect and remove volumes.

Container Data Is Temporary

Each container has its own writable layer on top of the image. Priya writes a file in a container, removes the container, then looks for the file in a new one:

docker run --name temp alpine sh -c "echo important > /data.txt"
docker rm temp
docker run --rm alpine cat /data.txt
Output

Click Run to see what this code prints.

The file died with the container. The new container started fresh from the image, which never contained /data.txt.

Named Volumes

A named volume is storage managed by Docker that exists independently of any container. Create one, then mount it into a container with -v VOLUME:PATH:

docker volume create notes-data
Output

Click Run to see what this code prints.

Three separate containers now use the same volume — two each add a line, the third reads the file:

docker run --rm -v notes-data:/data alpine sh -c 'echo "first note" >> /data/notes.txt'
docker run --rm -v notes-data:/data alpine sh -c 'echo "second note" >> /data/notes.txt'
docker run --rm -v notes-data:/data alpine cat /data/notes.txt
Output

Click Run to see what this code prints.

Every container was removed straight away (--rm), yet both notes survived, because they were written to the volume rather than to a container’s own layer. (If you mount a volume name that does not exist yet, Docker creates it automatically.)

Bind Mounts

A bind mount shares a folder from your own computer with a container — ideal during development, because changes appear immediately. Priya has a one-line website in ~/site/index.html and serves it with Nginx by mounting the folder over Nginx’s web root. The host path must be absolute, so $PWD (the current directory) is used:

docker run -d --name site -p 8080:80 -v "$PWD/site":/usr/share/nginx/html:ro nginx:alpine > /dev/null
sleep 1
curl -s http://localhost:8080/
Output

Click Run to see what this code prints.

She edits the file on her computer — no rebuild, no restart — and the container serves the new version at once:

echo "<h1>Priya's site, version 2</h1>" > site/index.html
curl -s http://localhost:8080/
Output

Click Run to see what this code prints.

Named volumeBind mount
Syntax-v notes-data:/data-v "$PWD/site":/usr/share/nginx/html
Where the data livesManaged by DockerA folder you choose on your computer
Best forDatabases and app data in any environmentSource code and config files during development
PortabilityWorks the same everywhereDepends on the host’s folder layout
The --mount Syntax

Docker also accepts a longer, more explicit form: --mount type=volume,source=notes-data,target=/data or --mount type=bind,source="$PWD/site",target=/usr/share/nginx/html,readonly. It does the same job and is easier to read in scripts.

Read-Only Mounts

The :ro at the end of Priya’s bind mount made it read-only inside the container. Nginx only needs to read the website, so even if the web server were compromised, it could not change the files:

docker exec site sh -c "echo hacked > /usr/share/nginx/html/index.html"
Output

Click Run to see what this code prints.

A Database That Keeps Its Data

The most important use of volumes is databases. Priya runs PostgreSQL 18 with a volume called pgdata for its data directory. (The official PostgreSQL 18 image keeps its data under /var/lib/postgresql. -e sets an environment variable — the image requires a password; lesson 9 covers this.)

docker run -d --name db -e POSTGRES_PASSWORD=secret -v pgdata:/var/lib/postgresql postgres:18-alpine
Output

Click Run to see what this code prints.

After a few seconds the database is ready. She creates a table and adds two rows with psql, PostgreSQL’s command-line client, which is included in the image:

docker exec db psql -U postgres -c "CREATE TABLE notes (id serial PRIMARY KEY, text text);" -c "INSERT INTO notes (text) VALUES ('Buy milk'), ('Learn Docker volumes');"
Output

Click Run to see what this code prints.

Now the real test — she deletes the database container completely:

docker rm -f db
Output

Click Run to see what this code prints.

She starts a brand-new container with the same docker run command (same volume), waits for it to be ready, and queries the table:

docker exec db psql -U postgres -c "SELECT * FROM notes;"
Output

Click Run to see what this code prints.

The data is all there. This is exactly how you upgrade a database container in practice: remove the old container, start one from the newer image with the same volume.

Mini Challenge · Predict the Output

Priya runs PostgreSQL without any -v option, adds data, then runs docker rm -f db and starts a new database container. What does SELECT * FROM notes; return?

Choose one answer

Managing Volumes

docker volume ls
Output

Click Run to see what this code prints.

(The listing was taken before PostgreSQL was started, so only notes-data appears.) docker volume inspect shows where Docker keeps a volume on the host:

docker volume inspect notes-data
Output

Click Run to see what this code prints.

Docker will not remove a volume that a container is using:

docker volume rm pgdata
Output

Click Run to see what this code prints.

After removing the containers, Priya deletes the notes volume by name, then removes every volume no container uses with docker volume prune -a:

docker rm -f db site > /dev/null
docker volume rm notes-data
docker volume prune -a -f
Output

Click Run to see what this code prints.

Removing a Volume Deletes the Data

There is no undo. Before pruning volumes on a real system, make sure nothing you need lives in them — and back up databases regularly, for example with pg_dump.

Common Mistakes

Avoid These Mistakes
  • Running a database without a volume and losing everything when the container is replaced.
  • Mounting a volume at the wrong path, so the database still writes inside the container — check the image’s documentation.
  • Using a relative host path such as -v site:/usr/share/nginx/html, which creates a named volume called site instead of a bind mount.
  • Running docker volume prune without checking what it will delete.

Frequently Asked Questions

For databases, use the database’s own tool (pg_dump, mysqldump) through docker exec. For files, run a temporary container that mounts the volume and a host folder, and create an archive: docker run --rm -v notes-data:/data -v "$PWD":/backup alpine tar czf /backup/notes.tar.gz -C /data .

They can be, because files cross from your computer into Docker Desktop’s virtual machine. On Windows, keep projects inside WSL for much better performance.

Storage kept in memory only (--tmpfs /cache), for temporary files that should never be written to disk.

Key Takeaways

  • Files written inside a container are lost when the container is removed.
  • Named volumes (-v name:/path) keep data independently of containers — use them for databases.
  • Bind mounts (-v "$PWD/dir":/path) share your own folders, ideal for development.
  • Add :ro when a container only needs to read the files.
  • docker volume ls, inspect, rm and prune manage volumes; removing a volume deletes its data.

Summary

Your containers can now keep their data safely. Next you will configure containers without rebuilding them, using environment variables — and learn how to handle passwords properly.

Next Lesson →

Environment Variables and Configuration