How do you back up and restore data in a Docker volume?
Quick Answer
Run a temporary, throwaway container that mounts the target volume alongside a bind-mounted host directory, and use a simple archiving tool like tar to copy the volume's contents out to (for backup) or in from (for restore) a compressed archive on the host. This works because a volume can be mounted by any container, regardless of which "real" container normally uses it — the backup/restore process doesn't need to touch or understand the application at all.
Detailed Answer
Backing up a volume
docker run --rm \
-v my-app-data:/source:ro \
-v $(pwd):/backup \
alpine \
tar czf /backup/my-app-data-backup.tar.gz -C /source .
Breaking this down:
-v my-app-data:/source:ro— mounts the volume you want to back up, read-only via:ro, so the backup process can't accidentally modify the live data while reading it.-v $(pwd):/backup— a bind mount, giving the temporary container access to your current host directory, so the archive ends up somewhere you can actually reach it afterward.alpine— a minimal, throwaway image, chosen because it includestarand little else needed for this one-off task.tar czf /backup/my-app-data-backup.tar.gz -C /source .— compresses everything in/source(the mounted volume) into a single archive, written to/backup(the bind-mounted host directory).--rm— removes this temporary container once the command finishes, since it has no purpose beyond this one backup.
Restoring from a backup
docker volume create my-app-data-restored
docker run --rm \
-v my-app-data-restored:/target \
-v $(pwd):/backup \
alpine \
tar xzf /backup/my-app-data-backup.tar.gz -C /target
The reverse process: create a fresh volume (or reuse an existing one, if restoring in place), mount it as the extraction target, and unpack the archive into it using the same kind of temporary, throwaway container.
Why this pattern works: volumes aren't tied to any specific "owning" container
The key idea: a named volume isn't permanently bound to whichever container originally used it. Any container can mount it, including a completely unrelated, temporary one whose only job is to run a backup/restore command. This same property is what makes volumes useful for migrating data between different application versions, or even different applications entirely — as long as both sides agree on the data format inside the volume.
Database-specific backup tools are usually still the better choice for real databases
docker exec my-postgres pg_dump -U postgres mydb > backup.sql
For an actual running database, native backup tools — pg_dump, mysqldump, and equivalents — are generally better than a raw filesystem-level tar of the volume. A live database's on-disk files can be mid-write and inconsistent if you archive them directly while it's running, unless you stop it first or the tool specifically supports safe hot-backup snapshotting. A proper dump tool guarantees a consistent, valid backup by using the database's own transactional guarantees, instead of copying raw files.
Automating this as a scheduled task
# A cron job, or a scheduled CI/CD pipeline step, running the backup command
# above on a regular schedule, pushing the resulting archive to durable,
# off-host storage (cloud object storage, a dedicated backup server) --
# never leaving backups only on the SAME host as the live data.
This follows the same backup principle as any stateful system: automate it on a regular schedule, store it somewhere genuinely separate from the live data so one host failure can't destroy both, and periodically test it by actually performing a restore. An untested backup isn't a real backup, no matter what command produced it.