Migrating a Docker volume between hosts moves persistent container data without depending on the source host's local storage layout. The usual pattern is to stop the writer, export the named volume to a portable tar archive, copy that archive to the destination host, and restore it into a new volume there.

Named volumes are local resources on each Docker host, so the destination machine cannot read the source host's volume directly. A short-lived helper container can mount the volume with --mount, write the archive into a host directory, and then unpack that same archive into a destination volume without needing the application image itself.

The flow below was verified against current Docker Engine volume behavior using a standard local named volume and an alpine helper container. Stop every container that writes to the source volume before exporting it, restore only into a new or empty destination volume, and keep the same container mount path on the receiving workload so the migrated files appear where the application expects them.

Steps to migrate a Docker volume between hosts:

  1. Stop the container that writes to the source volume so the archive is taken from a consistent on-disk state.
    $ docker container stop notes-db
    notes-db

    If multiple containers write to the same volume, stop all of them before exporting it.

    Leaving an active writer running during the export can capture half-written files or application state that does not replay cleanly on the destination host.

  2. Create a host directory on the source machine for the exported archive.
    $ mkdir -p /srv/docker-backups

    The helper container mounts this directory as a bind mount so the tarball lands on the host instead of inside a disposable container filesystem.

  3. Export the named volume into a compressed tar archive from a short-lived helper container.
    $ docker run --rm --mount source=notes-data,target=/from --mount type=bind,src=/srv/docker-backups,dst=/backup alpine tar -czf /backup/notes-data.tar.gz -C /from .

    Docker documentation currently prefers --mount over -v because it is more explicit and supports the full set of volume options.

  4. List the archive contents before copying it away from the source host.
    $ tar -tzf /srv/docker-backups/notes-data.tar.gz
    ./
    ./app.sqlite
    ./settings.ini
    ./uploads/
    ./uploads/readme.txt

    This quick check confirms that the tarball contains the expected volume paths before the transfer step begins.

  5. Create the same archive directory on the destination host so the transferred tarball has a predictable landing path.
    $ ssh admin@docker-b.example.com mkdir -p /srv/docker-backups
  6. Copy the archive from the source host to the destination host.
    $ scp /srv/docker-backups/notes-data.tar.gz admin@docker-b.example.com:/srv/docker-backups/

    Replace admin, docker-b.example.com, and the host path with the real destination values used in the environment.

  7. Create the destination volume on the receiving host before restoring the archive into it.
    $ docker volume create notes-data
    notes-data

    Restore into a new or empty volume only. Reusing a volume that already contains data can leave stale files mixed with the migrated copy.

  8. Restore the tar archive into the destination volume from another short-lived helper container.
    $ docker run --rm --mount source=notes-data,target=/to --mount type=bind,src=/srv/docker-backups,dst=/backup alpine tar -xzf /backup/notes-data.tar.gz -C /to
  9. Inspect the restored volume contents before attaching the application workload to it.
    $ docker run --rm --mount source=notes-data,target=/data alpine ls -al /data
    total 20
    drwxr-xr-x    3 root     root          4096 Apr 16 08:49 .
    drwxr-xr-x    1 root     root          4096 Apr 16 08:49 ..
    -rw-r--r--    1 root     root            14 Apr 16 08:49 app.sqlite
    -rw-r--r--    1 root     root            13 Apr 16 08:49 settings.ini
    drwxr-xr-x    2 root     root          4096 Apr 16 08:49 uploads

    Docker copies files from the container destination path into an empty volume by default when that volume is first mounted by a workload container. Restoring the archive before the application starts avoids mixing those seed files with migrated data, and the volume-nocopy mount option is available when an empty first mount must not copy image-side content.

  10. Attach the restored volume to the destination container or stack at the same container path used on the source host.

    The application start command is workload-specific, but the mount path must stay the same or the restored data will not appear where the container expects it.