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 formatCONTAINER: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
# 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-logsThree directions, all using the same docker cp.
Syntax in detail
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:
# 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.txtGotcha: trailing /. matters. dir/ vs dir/. behaves differently — same behavior as cp -r in shell.
Stream form (tar)
# 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:/destUseful for backup pipelines and when you cannot use docker run --rm to mount.
Common mistakes
Forgetting that cp to the writable layer is ephemeral
$ 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
# 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:
$ docker cp api:/var/log/access.log .
$ ls -la access.log
-rw-r--r-- 1 1000 1000 ... access.log # UID 1000 from inside containerSometimes UID 1000 happens to match your user; sometimes it does not. Use chown $(id -u):$(id -g) ... after the copy if needed.
Confusing direction
# 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 → containerThe 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 cpwrites 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
rsyncoverdocker execfor delta-only transfers, or just use a bind mount. - Across hosts:
docker save | ssh ... | docker loadfor images;taroversshfor 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 cpfrom a stopped DB container to host as a snapshot. Or viatarthrough 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
$ 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 reloadQuick 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
# 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
# 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:/destinationUseful when you need to filter on the way (tar flags) or when the destination does not have shell-friendly paths.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.
Comments
No comments yet