Back to Blog
Guide7 min read2026-05-01

Docker Volumes: Persistent Storage for Containers Explained

Understand Docker volumes, bind mounts, and tmpfs — and learn when to use each for reliable persistent storage in containerized applications.

Why Containers Lose Data by Default

Containers are ephemeral. When a container stops or is removed, everything written to its filesystem disappears. For stateless applications this is fine — but databases, file uploads, logs, and caches need data to survive container restarts.

Docker solves this with three storage mechanisms: named volumes, bind mounts, and tmpfs mounts.

Named Volumes (Recommended for Production)

Named volumes are managed by Docker and stored in Docker's storage area on the host (typically /var/lib/docker/volumes/). They're the preferred method for persisting data in production.

# Create a named volume
docker volume create pg_data

# Use it when running a container
docker run -d   --name postgres   -e POSTGRES_PASSWORD=secret   -v pg_data:/var/lib/postgresql/data   postgres:16-alpine

In a docker-compose.yml:

services:
  db:
    image: postgres:16-alpine
    volumes:
      - pg_data:/var/lib/postgresql/data

volumes:
  pg_data:

The pg_data volume persists even after docker compose down. Only docker compose down -v removes it.

Volume Commands

docker volume ls                    # list all volumes
docker volume inspect pg_data       # show volume details and mountpoint
docker volume rm pg_data            # remove a volume (container must be stopped)
docker volume prune                 # remove all unused volumes

Bind Mounts (Best for Local Development)

Bind mounts map a directory on your host machine directly into the container. Changes on the host are immediately visible inside the container — perfect for hot-reload development.

docker run -d   -p 3000:3000   -v $(pwd):/app   -v /app/node_modules   my-app:dev

The second -v /app/node_modules is an anonymous volume that prevents the host's node_modules from overwriting the container's — a common gotcha on macOS.

In docker-compose.yml:

services:
  api:
    build: .
    volumes:
      - .:/app           # bind mount: host source → container
      - /app/node_modules  # anonymous volume: protect container's node_modules

Avoid bind mounts in production — they couple your container to a specific host path.

tmpfs Mounts (In-Memory Storage)

tmpfs mounts store data in the host's memory — data is fast but lost when the container stops. Useful for sensitive temporary data you explicitly don't want persisted to disk.

docker run -d   --tmpfs /tmp:rw,noexec,nosuid,size=100m   my-app:latest

Or in docker-compose.yml:

services:
  api:
    image: my-app:latest
    tmpfs:
      - /tmp:size=100m

Backing Up and Restoring Volumes

Backup a named volume to a tar archive:

docker run --rm   -v pg_data:/data   -v $(pwd):/backup   alpine tar czf /backup/pg_data.tar.gz -C /data .

Restore from backup:

docker run --rm   -v pg_data:/data   -v $(pwd):/backup   alpine tar xzf /backup/pg_data.tar.gz -C /data

Volume Permissions

Databases and applications often run as non-root users. Set ownership when initializing a volume:

FROM node:20-alpine
WORKDIR /app

# Create uploads directory owned by the node user
RUN mkdir -p /app/uploads && chown node:node /app/uploads
VOLUME /app/uploads

USER node

Choosing the Right Storage Type

Use CaseRecommended Storage
Database files (PostgreSQL, MySQL)Named volume
File uploadsNamed volume
Source code (local dev)Bind mount
Sensitive temp filestmpfs
Cache (Redis)Named volume
Config filesBind mount or secrets

Databases in Production: Use Managed Services

For production workloads, self-managed databases in containers require operational expertise — backups, failover, replication, and disk management. PandaStack offers managed PostgreSQL, MySQL, Redis, and MongoDB databases with automated backups, point-in-time recovery, and connection pooling built in.

You get the data persistence without the operational burden. Pair a managed database with your containerized application deployed via:

npm install -g @pandastack/cli
panda deploy --type container --repo your-org/your-repo

Connect your container to the managed database using environment variables set from [dashboard.pandastack.io](https://dashboard.pandastack.io). See [docs.pandastack.io](https://docs.pandastack.io) for the full guide.

Ready to deploy?

Start free on PandaStack — no credit card required.

Start free on PandaStack

More in Guide

Browse all Guide articles →

See also