Skip to content
Codeloom
Docker

Docker Volumes and Persistent Storage

Manage persistent data in Docker — named volumes, bind mounts, tmpfs, backup strategies, and volume drivers for production.

·3 min read · By Codeloom
Beginner 8 min read

What you'll learn

  • Why containers need external storage for persistent data
  • Named volumes vs bind mounts vs tmpfs
  • Managing volumes in Docker and Compose
  • Backup and restore strategies

Prerequisites

  • Docker basics (running containers)

Containers are ephemeral — when they stop, their filesystem is gone. Volumes persist data beyond the container lifecycle. They are how you keep database files, uploads, and configuration alive.

Three types of storage

Named volumes

Docker manages the storage location. Best for production data.

docker volume create mydata
docker run -v mydata:/var/lib/postgresql/data postgres

Bind mounts

Map a host directory into the container. Best for development.

docker run -v $(pwd)/src:/app/src myapp

tmpfs

In-memory storage. Gone when the container stops. Good for sensitive data.

docker run --tmpfs /tmp myapp

Named volumes in detail

# Create
docker volume create pgdata

# List
docker volume ls

# Inspect
docker volume inspect pgdata

# Remove
docker volume rm pgdata

# Remove all unused volumes
docker volume prune

Using volumes

# Named volume
docker run -d --name db -v pgdata:/var/lib/postgresql/data postgres:16

# Anonymous volume (Docker generates a name)
docker run -d -v /var/lib/postgresql/data postgres:16

Volumes in Docker Compose

services:
  postgres:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data

  api:
    build: .
    volumes:
      - ./src:/app/src        # bind mount for development
      - node_modules:/app/node_modules  # named volume for deps

volumes:
  pgdata:
  node_modules:

Bind mounts for development

services:
  api:
    build: .
    volumes:
      - ./src:/app/src:ro  # read-only bind mount
    environment:
      - NODE_ENV=development

The :ro flag makes the mount read-only inside the container.

Sharing volumes between containers

services:
  writer:
    image: myapp
    volumes:
      - shared:/data

  reader:
    image: myapp
    volumes:
      - shared:/data:ro

volumes:
  shared:

Backup and restore

Backup a volume

docker run --rm -v pgdata:/source -v $(pwd):/backup alpine \
    tar czf /backup/pgdata-backup.tar.gz -C /source .

Restore a volume

docker run --rm -v pgdata:/target -v $(pwd):/backup alpine \
    sh -c "cd /target && tar xzf /backup/pgdata-backup.tar.gz"

Volume permissions

A common issue: the container user does not have permission to write to the volume.

FROM node:20
RUN mkdir -p /app/data && chown -R node:node /app/data
USER node
VOLUME /app/data

Volume drivers

For production, use volume drivers for cloud storage:

# AWS EFS
docker volume create --driver local \
    --opt type=nfs \
    --opt o=addr=fs-123.efs.us-east-1.amazonaws.com,rw \
    --opt device=:/ \
    efs-data

Summary

Use named volumes for production data (databases, uploads). Use bind mounts for development (live code reload). Use tmpfs for sensitive temporary data. Back up volumes regularly and use read-only mounts where possible. Volumes are the bridge between Docker’s ephemeral containers and your persistent data.