Skip to content

Docker Volumes Explained: Bind Mount vs Named Volume

Bind mount vs named volume in Docker: how they differ, when to use each, where data lives, permissions, backups, and the down -v data-loss trap.

SDSysadmin Desk June 20, 2026 9 min read
Diagram-style cover comparing a bind mount from a host folder and a Docker named volume attached to a container

A container’s filesystem is disposable. Remove the container and everything written inside it is gone — which is exactly what you want for the app binary, and exactly what you don’t want for a database. Volumes are how data outlives the container that wrote it.

Docker gives you two ways to do this, and people mix them up constantly. A bind mount maps a folder you choose on the host into the container. A named volume is storage Docker creates and manages for you, referenced by a name instead of a path. They look similar in a -v flag, but they behave differently and suit different jobs.

This guide lays out the real differences, when each one is the right tool, where named volumes actually live, the permission gotchas that trip people up, how to back them up, and the down -v mistake that has erased more than one production database.

The two mount types side by side

Start with the shapes, because the syntax is where the confusion begins. Both use -v host-side:container-side, but the host side is what differs:

# Bind mount — host side is a PATH you control
docker run -v /home/sam/app:/usr/src/app myimage

# Named volume — host side is a NAME Docker manages
docker run -v app-data:/usr/src/app myimage

That first character tells you which is which. A leading / or ./ means a path, so it’s a bind mount. A bare word like app-data means a named volume Docker looks after.

Bind mount vs named volume at a glance

You specify Bind mount: an exact host path. Named volume: just a name.
Managed by Bind mount: you. Named volume: Docker.
Lives where Bind mount: wherever you point it. Named volume: /var/lib/docker/volumes/.
Edit from host Bind mount: yes, directly. Named volume: not meant to (go through a container).
Best for Bind mount: source code, config files. Named volume: databases, app data.
Removed by down -v Bind mount: no (it's your folder). Named volume: yes.
Portability Bind mount: tied to host path. Named volume: portable, Docker-managed.

When to use a bind mount

Reach for a bind mount when you want to see and edit the files yourself, from the host, right now.

The classic case is development. You bind-mount your source code into the container so that editing a file in your editor is instantly reflected inside the running app — no rebuild, no copy step:

services:
  web:
    build: .
    volumes:
      - ./src:/usr/src/app/src    # live-edit code from the host
    ports:
      - "3000:3000"

The other strong use is configuration. Mounting a single config file into a container lets you manage it with your normal tools and version it in git:

services:
  proxy:
    image: nginx
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro   # :ro = read-only

Note the :ro on the end — read-only. For config the container should never modify, that’s a good habit; it stops a misbehaving process from rewriting your file.

What bind mounts are bad at is portability. The path /home/sam/app exists on your machine and probably nowhere else. Hardcode that into a production stack and the setup breaks the moment you move it to a server with a different layout.

When to use a named volume

Use a named volume for data the application owns and must keep: databases, user uploads, anything generated at runtime that you don’t hand-edit.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: change-me
    volumes:
      - db-data:/var/lib/postgresql/data   # named volume

volumes:
  db-data:

The volumes: block at the bottom declares db-data so Docker manages it. The advantages over a bind mount here are concrete. Docker sets correct ownership when it creates the volume, so you dodge most permission headaches. There’s no host path baked in, so the same file works on your laptop and the server. And the data is decoupled from any container — destroy and recreate the Postgres container as often as you like, the volume stays.

Where named volumes actually live

A common question: if Docker manages the volume, where’s the data? On Linux, named volumes sit under Docker’s data directory:

/var/lib/docker/volumes/<volume-name>/_data

You can ask Docker for the exact location and details of any volume:

docker volume inspect db-data

The Mountpoint field in the output is the real path on disk. Useful commands for managing volumes:

# List all volumes
docker volume ls

# Inspect one (shows the mountpoint and driver)
docker volume inspect db-data

# Create one explicitly (Compose usually does this for you)
docker volume create db-data

# Remove a specific volume (must not be in use)
docker volume rm db-data

The permissions problem (and how to actually fix it)

Bind mounts are where “permission denied” shows up, and the reason is simple once you see it. A bind mount keeps the host’s ownership. Files owned by UID 1000 on the host arrive in the container still owned by UID 1000. If the process inside the container runs as a different user, it can’t read or write them.

The wrong fix is chmod -R 777 on the folder. It papers over the problem and opens the files to everyone. The right fix is to make the UIDs line up.

Either run the container as the user that owns the files:

docker run --user $(id -u):$(id -g) -v "$PWD":/app myimage

Or change the host folder’s ownership to match the UID the container expects (check the image’s docs for which user it runs as):

sudo chown -R 1000:1000 ./data

Named volumes mostly sidestep this. When Docker first creates a named volume for a container, it initializes the contents with the image’s existing ownership, so the process usually finds files it can write. It’s one of the quieter reasons named volumes are easier for databases.

Permission fixes — pick the right one

Align the container user --user $(id -u):$(id -g) — run as the host file owner.
Fix host ownership chown the bind-mounted folder to the UID the image uses.
Switch to a named volume For app data, let Docker handle ownership at creation time.
chmod 777 everything Avoid. Hides the real issue and weakens file security.

Backing up a named volume

Because named volumes don’t map to an obvious host folder, backing them up needs one extra step: mount the volume into a throwaway container alongside a host folder, then archive it across.

# Back up the 'db-data' volume to a tar.gz in the current folder
docker run --rm \
  -v db-data:/data \
  -v "$PWD":/backup \
  alpine tar czf /backup/db-data.tar.gz -C /data .

That spins up a tiny Alpine container, mounts the volume read side at /data and your current directory at /backup, tars the contents, and removes itself (--rm). To restore into a fresh volume, reverse it:

docker run --rm \
  -v db-data:/data \
  -v "$PWD":/backup \
  alpine sh -c "tar xzf /backup/db-data.tar.gz -C /data"

The down -v trap

This is the one that costs people data, so read it carefully. docker compose down and docker compose down -v look nearly identical and behave very differently.

Plain down stops and removes the containers and the default network. Named volumes stay. Run up -d again and your database is right where it was.

Add -v and Compose also deletes every named volume declared in the file. On a stack with a database, that erases the database. No recycle bin, no undo.

docker compose down       # safe — keeps named volumes (your data)
docker compose down -v    # DESTROYS named volumes declared in the file

Before you run down -v

  • List the named volumes in the volumes: block of your compose file
  • Check whether any hold a database, uploads, or anything you can't regenerate
  • Back up the volume first if the data matters (tar method or a db dump)
  • Confirm you want a clean slate, not just a stop or restart
  • For a normal stop, use plain 'down' or 'stop' instead

Choosing between them

A short decision rule covers most cases. If you’ll edit the files yourself from the host — source code in development, a config file you version in git — use a bind mount. If the application owns the data and just needs it to persist — a database, user uploads, runtime state — use a named volume.

And there’s no rule against using both in one container. A web app might bind-mount its source for live editing while keeping its database in a named volume. They’re separate mounts on separate paths, and mixing them is normal.

For the bigger picture of how volumes fit into multi-container apps, see the Docker Compose beginner guide, and browse the Docker & Containers guides for more storage and networking topics.

Frequently asked questions

What is the main difference between a bind mount and a named volume?

A bind mount maps a specific folder on the host into the container, so you control the exact path and can edit files directly. A named volume is storage Docker creates and manages in its own area, referenced by name rather than a host path. Bind mounts are best for code and config you edit; named volumes are best for application data like databases.

Where are Docker named volumes stored on disk?

On Linux they live under /var/lib/docker/volumes//_data. You can see the exact path with docker volume inspect . You generally shouldn't edit files there by hand — manage the data through a container instead. On Docker Desktop the volumes sit inside the Linux VM, not directly on your Mac or Windows filesystem.

Why do I get permission denied errors with bind mounts?

Bind mounts keep the host's ownership and permissions. If the container's process runs as a different UID than the host files' owner, it can't read or write them. Fix it by aligning the UID (run the container as the right user, or chown the host folder), not by making everything 777. Named volumes avoid this because Docker sets ownership when it creates them.

Does docker compose down delete my volumes?

Plain docker compose down removes containers and the default network but keeps named volumes, so your data survives. Adding -v deletes the named volumes declared in the file, which wipes databases and uploads. Bind mounts are never removed by down because they're just host folders Docker doesn't own.

How do I back up a Docker named volume?

Run a temporary container that mounts the volume and a host folder, then tar the volume's contents to the host. For example: docker run --rm -v myvol:/data -v $(pwd):/backup alpine tar czf /backup/myvol.tar.gz -C /data . For databases, a proper dump (like pg_dump or mysqldump) is usually safer than a raw file copy.

Can I use both a bind mount and a named volume in the same container?

Yes, and it's common. A typical web app bind-mounts its source code for live editing while using a named volume for the database. They're independent mounts on different paths, so mixing them in one service or compose file is perfectly normal.

Which should I use in production?

For application data that must persist — databases, user uploads — use named volumes. They're portable, managed by Docker, and decoupled from any host path. Reserve bind mounts for configuration files and, in development, source code. Hardcoding host paths into production with bind mounts makes the setup fragile and harder to move.

Sources & further reading

Official vendor documentation referenced while writing this guide.

SD

Sysadmin Desk

Infrastructure & Cloud

Hands-on guidance for infrastructure, virtualization, and containers — Hyper-V, VMware, Docker, and the day-to-day operations work that keeps environments running.

MCSA Guru provides independent, educational IT guidance. Microsoft, Windows, Windows Server, Microsoft 365, Exchange, and Microsoft Teams are trademarks of Microsoft Corporation; Docker is a trademark of Docker, Inc. MCSA Guru is not affiliated with or endorsed by Microsoft or Docker. Always test changes in a safe environment before applying them in production.

Related guides

Fixing something right now?

Jump straight into the guide library or search for the exact error or task you are dealing with.