Migrating a Docker named volume to a host path moves persistent container data into a bind mount that can be inspected, backed up, and managed with normal host tools. The migration is complete only when the workload starts again from that host directory instead of the original volume.

The Docker-side workflow is to confirm the current mount target, stop the writer, copy the named volume into a host directory from a short-lived helper container, and recreate the workload with a bind mount that uses the same container path. Keeping the container path unchanged lets the application find the migrated files where it already expects them.

Unlike a named volume, a bind mount does not seed an empty target path with files from the image, and mounting over a populated container directory hides the image-side files underneath it. Copy the data before switching the mount, use a new or intentionally empty host directory, and keep the original named volume until the restarted workload passes its own health check.

Steps to migrate Docker volume data to a host path:

  1. Inspect the current container mount so the source volume name and destination path are explicit before anything changes.
    $ docker container inspect --format '{{range .Mounts}}{{.Type}} {{if .Name}}{{.Name}}{{else}}{{.Source}}{{end}} {{.Destination}}{{println}}{{end}}' notes-app
    volume notes-data /var/lib/notes

    The last field is the container path that the replacement bind mount must keep. Related: How to inspect container details in Docker

  2. Stop the container that writes to the volume so the copied files come from a consistent on-disk state.
    $ docker container stop notes-app
    notes-app

    Do not remove the original volume yet. Keep it available until the recreated workload starts cleanly and the application-level check succeeds.

  3. Create the host directory that will receive the migrated files.
    $ sudo mkdir -p /srv/notes-data

    The path must exist on the machine that runs the Docker daemon. On Docker Desktop, use a local path that is shared with Docker.

    Use a new or intentionally empty directory, because copying into a populated host path can leave old files mixed with the migrated data.

  4. Copy the named volume into the host directory from a short-lived helper container.
    $ docker run --rm --mount source=notes-data,target=/from,readonly --mount type=bind,src=/srv/notes-data,dst=/to alpine cp -a /from/. /to

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

  5. List the host directory so the migrated files are visible before the workload is recreated.
    $ ls -al /srv/notes-data
    total 16
    drwxr-xr-x 3 root root 4096 Apr 16 09:07 .
    drwxr-xr-x 3 root root 4096 Apr 16 09:06 ..
    -rw-r--r-- 1 root root   16 Apr 16 09:07 app.env
    drwxr-xr-x 2 root root 4096 Apr 16 09:07 uploads

    If ownership must match a non-root container user, correct it on the host before the container starts again.

  6. Remove the stopped container so it can be recreated with a different mount type.
    $ docker container rm notes-app
    notes-app

    Mount definitions are fixed when the container is created, so switching from a named volume to a bind mount requires recreation.

  7. Recreate the container with the same image and runtime options, but replace the named volume with a bind mount that targets the same container path.
    $ docker run -d --name notes-app --restart unless-stopped --mount type=bind,src=/srv/notes-data,dst=/var/lib/notes <original-image>

    Reuse the original ports, environment variables, networks, command, and restart policy here. Only the storage definition should change.

    The bind mount hides any files baked into the image at /var/lib/notes, so copy the original volume contents first and keep the same destination path.

  8. Inspect the recreated container so the mount now shows a bind source instead of a volume name.
    $ docker container inspect --format '{{range .Mounts}}{{.Type}} {{if .Name}}{{.Name}}{{else}}{{.Source}}{{end}} {{.Destination}}{{println}}{{end}}' notes-app
    bind /srv/notes-data /var/lib/notes
  9. Verify the migrated files from inside the recreated container before deleting the original named volume.
    $ docker exec notes-app ls -al /var/lib/notes
    total 8
    drwxr-xr-x    4 root     root           128 Apr 16 09:07 .
    drwxr-xr-x    1 root     root          4096 Apr 16 09:09 ..
    -rw-r--r--    1 root     root            16 Apr 16 09:07 app.env
    drwxr-xr-x    3 root     root            96 Apr 16 09:07 uploads

    After this Docker-level check succeeds, run the application's own health endpoint, login flow, or smoke test before removing the original volume.