Skip to main content

How to copy files between a Docker container and the host?

docker cp is the simplest way to move files between a container and your host. It works in both directions, on running and stopped containers, and handles directories recursively.

Theory

TL;DR

  • Syntax: docker cp SRC DST. One side has format CONTAINER:PATH.
  • Works on both running and stopped containers.
  • Copies recursively for directories. Preserves ownership/permissions inside the container.
  • For ongoing host↔container sync, use bind mounts. For backup of volumes, use a tar via a helper container.
  • Cannot copy between two containers directly — pipe through host or use a shared volume.

Quick example

bash
# Get a config file out of a container for inspection $ docker cp nginx-c:/etc/nginx/nginx.conf ./nginx.conf # Drop a SQL fix into a running db $ docker cp ./hotfix.sql db:/tmp/hotfix.sql $ docker exec db psql -U postgres -f /tmp/hotfix.sql # Copy a whole directory of logs out $ docker cp web:/var/log/nginx ./nginx-logs

Three directions, all using the same docker cp.

Syntax in detail

bash
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH docker cp [OPTIONS] CONTAINER:SRC_PATH - # to stdout (as tar) docker cp [OPTIONS] - CONTAINER:DEST_PATH # from stdin (tar)

Flags:

  • -a / --archive = preserve file owner/group/mode (default behavior since recent versions).
  • -L / --follow-link = follow symbolic links in SRC.

Source/destination behavior

Docker's behavior depends on whether SRC and DEST are existing directories:

bash
# Both are existing dirs → copy SRC contents into DEST docker cp /host/dir/. container:/dst/ # note the trailing /. # SRC is dir, DEST does not exist → SRC becomes DEST docker cp /host/dir container:/newdst # /newdst now contains what /host/dir had # SRC is file, DEST is existing dir → file goes inside DEST docker cp /host/file.txt container:/dst/ # → /dst/file.txt # SRC is file, DEST is new path → file is renamed docker cp /host/file.txt container:/dst/renamed.txt

Gotcha: trailing /. matters. dir/ vs dir/. behaves differently — same behavior as cp -r in shell.

Stream form (tar)

bash
# Stream a tar of /etc out of the container docker cp container:/etc - | tar tf - # list contents # Pipe arbitrary content into a path inside container tar cf - mydir | docker cp - container:/dest

Useful for backup pipelines and when you cannot use docker run --rm to mount.

Common mistakes

Forgetting that cp to the writable layer is ephemeral

bash
$ docker cp ./config.yml api:/etc/config.yml # Edit applied. Container restart → file may persist (it is in writable layer). # But docker rm → file gone forever.

docker cp writes to the container's writable layer. Persists across docker stop/start of the same container. Lost on docker rm. For permanent changes, edit your image (Dockerfile) or use a volume / bind mount.

Trying to copy between two containers

bash
# WRONG: not supported $ docker cp source:/file target:/file Error: invalid arguments # Use a stream: $ docker cp source:/file - | docker cp - target:/file # Or a shared volume.

Surprised at file owner on the host

The container often runs as a specific user (root, or app-specific). Files extracted with docker cp keep their UIDs, which may be unfamiliar on the host:

bash
$ docker cp api:/var/log/access.log . $ ls -la access.log -rw-r--r-- 1 1000 1000 ... access.log # UID 1000 from inside container

Sometimes UID 1000 happens to match your user; sometimes it does not. Use chown $(id -u):$(id -g) ... after the copy if needed.

Confusing direction

bash
# WRONG: this copies FROM host TO container, but the colon is on the wrong side $ docker cp container:./file ./file # error or surprise # RIGHT $ docker cp container:/path/file ./file # container → host $ docker cp ./file container:/path/file # host → container

The colon-separated form (container:path) is the container side; the other side is the host.

When to NOT use docker cp

  • Persistent data (databases, uploads): use named volumes. docker cp writes to the writable layer, which is the wrong place.
  • Live dev sync (edit-on-host, see-in-container): bind mount, not docker cp. Faster, no copy step.
  • Large directories repeatedly: consider rsync over docker exec for delta-only transfers, or just use a bind mount.
  • Across hosts: docker save | ssh ... | docker load for images; tar over ssh for raw files.

Real-world usage

  • Pulling logs out of a misbehaving prod container before docker rm'ing it.
  • Injecting a quick fix (SQL, config snippet) into a running container as a stopgap. Permanent fix goes into the image.
  • Backups: docker cp from a stopped DB container to host as a snapshot. Or via tar through a helper container — docker run --rm -v vol:/data alpine tar cf - /data > backup.tar.
  • Debugging: copy a core dump or heap dump out of the container for analysis.

Follow-up questions

Q: Does docker cp work on a stopped container?


A: Yes. The container's filesystem (image + writable layer) exists as long as the container record does. You can cp in/out without starting it.

Q: Are there permission issues when copying into a running container?


A: Sometimes. The destination's directory permissions and the path's owner inside the container determine if the file ends up owned by root or by the app user. Use --chown flag if you need a specific UID/GID — but docker cp does not have that flag like COPY --chown=. Workaround: docker exec ... chown after the copy.

Q: What is the difference between docker cp and docker exec ... cat ... > file?


A: docker cp understands directory recursion, preserves metadata, and works on stopped containers. The exec ... cat trick works for single files on running containers only. docker cp is the right primitive.

Q: How do I copy from a container to a different host's container?


A: Pipe through the network: docker cp src:/file - | ssh remote 'docker cp - dst:/file'. Or, if both hosts can reach the same registry, build an image with the file and pull it on the other side.

Q: (Senior) When is docker cp not the right primitive even for one-off copies?


A: Anything you find yourself doing repeatedly should be a volume. Anything you want versioned (config files) should be in the Dockerfile or a config-management volume. Anything large and frequently changing belongs in object storage with the container reading at startup. docker cp is for ad-hoc, one-shot, debug-style copies.

Examples

Pull config out, edit, push back

bash
$ docker cp web:/etc/nginx/nginx.conf ./nginx.conf $ vi ./nginx.conf $ docker cp ./nginx.conf web:/etc/nginx/nginx.conf $ docker exec web nginx -s reload

Quick one-off config tweak. The proper fix would be to bake the config into a new image or mount it from host, but for an emergency tweak this works.

Backup with tar via a helper container

bash
# Backup a volume's contents (container does not need to be running) $ docker run --rm \ -v pgdata:/data \ -v $PWD:/backup \ alpine \ tar czf /backup/pgdata-$(date +%F).tar.gz -C /data .

Better than docker cp for volumes because volumes are not part of any single container's writable layer.

Stream a directory through a tar pipe

bash
# Get all logs as a tar stream $ docker cp web:/var/log/nginx - > logs.tar $ tar xf logs.tar # Inverse: push a tar into a container $ tar cf - some-dir | docker cp - container:/destination

Useful when you need to filter on the way (tar flags) or when the destination does not have shell-friendly paths.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Comments

No comments yet