Persistent Volumes

Storage patterns for keeping container data durable across restarts and upgrades

created: Sat Mar 14 2026 00:00:00 GMT+0000 (Coordinated Universal Time) updated: Sat Mar 14 2026 00:00:00 GMT+0000 (Coordinated Universal Time) #containers#docker#storage

Introduction

Containers are disposable, but application data usually is not. Persistent volumes provide storage that survives container restarts, recreation, and image upgrades.

Purpose

Use persistent volumes to:

  • Preserve databases, uploads, and application state
  • Separate data lifecycle from container lifecycle
  • Simplify backup and restore workflows
  • Reduce accidental data loss during redeployments

Architecture Overview

Docker storage typically falls into three categories:

  • Named volumes: managed by Docker and usually the best default for persistent app data
  • Bind mounts: direct host paths mounted into a container
  • Tmpfs mounts: memory-backed storage for temporary data

Storage Patterns

Named volumes

Named volumes are portable within a host and reduce the chance of coupling to host directory layouts.

docker volume create postgres-data
docker run -d \
  --name db \
  -v postgres-data:/var/lib/postgresql/data \
  postgres:16

Bind mounts

Bind mounts are useful when:

  • The application expects editable configuration files
  • You need direct host visibility into files
  • Backups are based on host file paths

Example:

docker run -d \
  --name caddy \
  -v /srv/caddy/Caddyfile:/etc/caddy/Caddyfile:ro \
  -v /srv/caddy/data:/data \
  caddy:2

Permissions and ownership

Many container storage issues come from mismatched UID and GID values between the host and containerized process. Check the image documentation and align ownership before assuming the application is broken.

Configuration Example

Compose example with named volumes:

services:
  app:
    image: ghcr.io/example/app:1.2.3
    volumes:
      - app-data:/var/lib/app
 
  db:
    image: postgres:16
    volumes:
      - db-data:/var/lib/postgresql/data
 
volumes:
  app-data:
  db-data:

Troubleshooting Tips

Data disappears after updating a container

  • Verify the service is writing to the mounted path
  • Check whether a bind mount accidentally hides expected image content
  • Inspect mounts with docker inspect <container>

Permission denied errors

  • Check ownership and mode bits on bind-mounted directories
  • Match container user expectations to host permissions
  • Avoid mounting sensitive directories with broad write access

Backups restore but the app still fails

  • Confirm the restored data matches the application version
  • Restore metadata such as permissions and database WAL files if applicable
  • Test restores on a separate host before using them in production

Best Practices

  • Use named volumes for most stateful container data
  • Use bind mounts deliberately for human-managed configuration
  • Keep backups separate from the production host
  • Record where every service stores its critical state
  • Test restore procedures, not only backup creation

References