Skip to content

Docker Storage

  • Docker uses a layered storage model based on a Union Filesystem (UnionFS). Image layers are read-only. When a container runs, Docker adds a thin read-write layer on top.
  • All runtime writes go into the container’s writable layer - this data is ephemeral and deleted with the container.
  • For persistent data, use volumes or bind mounts.

The storage driver manages how image layers and the container’s writable layer are stored and stacked on the host. Docker selects a driver automatically based on the OS.

DriverOSNotes
overlay2LinuxDefault and recommended. Uses overlayfs kernel feature. Best performance.
fuse-overlayfsLinux (rootless)Rootless Docker fallback when overlayfs needs root.
btrfsLinux (btrfs fs)Native driver for Btrfs filesystems.
zfsLinux (ZFS)Native driver for ZFS filesystems.
devicemapper(Removed)Removed from Docker Engine 25.0. Was used in RHEL/CentOS 7 thin-pool setups. Historical reference only - do not use on any new system.
aufs(Removed)Removed from Docker Engine 23.0 (February 2023). Was the Docker default on Ubuntu before overlay2. Required an out-of-tree kernel patch never merged into mainline Linux. Historical reference only.
vfsAll (testing)No copy-on-write. Every layer is a full copy. Extremely slow. Testing only.
Terminal window
# Check which storage driver Docker is using
docker info | grep "Storage Driver"
  • overlay2 uses the Linux overlayfs to present a merged view of multiple read-only layers + one read-write layer.

  • Copy-on-Write (CoW): When a container modifies a file from an image layer, the file is first copied to the writable layer, then modified. The original image layer is untouched.

  • Multiple containers based on the same image share the read-only layers - only their thin writable layers are unique.

    /var/lib/docker/overlay2/
    ├── <layer-id>/ # Each image layer
    │ ├── diff/ # Files in this layer
    │ ├── link # Short name for this layer
    │ └── lower # Pointer to parent layer
    └── <container-layer>/ # Container's writable layer
    └── merged/ # The unified filesystem view (what the container sees)

Everything Docker manages on the host lives under /var/lib/docker/ (or C:\ProgramData\docker\ on Windows).

/var/lib/docker/
├── image/ # Image layer metadata and digests
├── overlay2/ # Actual layer filesystems (storage driver specific)
├── containers/ # Per-container metadata, logs, and writable layers
├── volumes/ # Named volume data
└── networks/ # Network configuration
Terminal window
# Get the full storage path for a specific container
docker inspect <container-id> | grep -A5 GraphDriver
# See disk usage by Docker components
docker system df
docker system df -v # Verbose - shows per-image and per-container sizes
# Remove unused images, stopped containers, networks, and build cache
docker system prune
docker system prune -a # Also removes all unused images (not just dangling)
docker system prune -a --volumes # Nuclear option - also removes all unused volumes (DATA LOSS risk)

The writable layer technically allows you to modify files inside a running container, but you should never do this.

  • Containers should be treated as immutable objects - once deployed, their configuration is fixed.
  • If a fix, patch, or config change is needed: build and test a new container image, then replace the old container with it.
  • This keeps your running state reproducible and auditable.

Configuration vs. application data:

Container configApplication data
ExamplesNetwork settings, app config files, binariesDatabase records, user uploads, logs
Who changes itDevelopers / ops (via new image builds)The application itself at runtime
Correct storageBaked into image or mounted via bindNamed volume

The rule is simple: operators rebuild images to change configuration. Applications write data through mounted volumes - not into the container’s own writable layer.

Storage drivers manage the container’s own filesystem. For application data that needs to survive container restarts or be shared, see Docker Mounting.

Storage Driver LayerVolumesBind Mounts
Managed byDockerDockerHost OS
Survives container removalNoYesYes
PerformanceCoW overheadNativeNative
PortabilityN/AHighLow (host path)