docker cp — copy files between container and host

# Host → container
docker cp ./local-file.txt my-container:/app/file.txt

# Container → host
docker cp my-container:/app/logs/error.log ./error.log

# Copy a whole directory
docker cp my-container:/app/dist ./dist

You need to copy config files, logs, or build artifacts between your host and a container, such as copying a file from a container to the host.

Exactly one side of docker cp must be a container path

docker cp follows the shape of the Unix cp command, but a container path is prefixed with CONTAINER:. The other path is resolved on the host. The container may be running or stopped because Docker reads or writes its filesystem layer directly.

Use a container name instead of a short ID when the command will be documented or repeated. Quote paths that contain spaces, and use absolute container paths to avoid ambiguity. Docker interprets container paths relative to /, even when the leading slash is omitted.

docker ps -a --format 'table {{.Names}}	{{.Status}}'
docker cp "./release notes.txt" app:/tmp/release-notes.txt
docker cp app:/var/log/app.log ./artifacts/app.log

Check whether you are copying a directory or its contents

The source suffix changes directory behavior. Copying /app/dist to the current directory creates or replaces a dist entry. Copying /app/dist/. copies the contents inside that directory. The destination parent must exist when Docker cannot infer where to create it.

Copied files preserve container ownership information where possible

A file copied from a Linux container can arrive with a numeric user or group ID that does not map cleanly to the host account. A file copied into a container is normally created with root ownership unless archive behavior or the environment changes it. This can make the copy appear successful while the application still cannot read or update the file.

Inspect the result from both environments. If application ownership matters, fix it explicitly inside the container or copy into a writable staging path first. Avoid making files world-writable as a shortcut.

docker cp ./config.json app:/tmp/config.json
docker exec app ls -ln /tmp/config.json
docker exec --user root app chown 1000:1000 /tmp/config.json

Compare size or checksum instead of trusting the exit code alone

For logs and quick inspection, checking the destination size may be enough. For release artifacts, backups, or files used in a later deployment step, calculate a checksum on both sides. A matching SHA-256 digest confirms the copied bytes are identical.

sha256sum ./artifact.tar.gz
docker cp ./artifact.tar.gz app:/tmp/artifact.tar.gz
docker exec app sha256sum /tmp/artifact.tar.gz

Use docker cp for one-time transfer, not ongoing synchronization

docker cp is useful for extracting diagnostics, injecting a temporary config during debugging, or retrieving a build artifact. It does not establish a persistent relationship between the two paths. Use a bind mount for live development files, a named volume for persistent application data, and COPY in a Dockerfile for files that belong in every image built from that source.

Copy works on stopped containers too

# Even if the container is not running
docker ps -a | grep my-container   # Exited
docker cp my-container:/app/config.json ./config.json

Directory trailing slash behavior

Adding a trailing / to the source copies the directory contents (not the directory itself).

# Copies the dist/ directory itself
docker cp my-container:/app/dist ./

# Copies the contents of dist/ into ./dist-output/
docker cp my-container:/app/dist/. ./dist-output/

Use volumes for persistent sharing instead

A bind mount reflects later host changes in the container. It is a better fit for source code, local configuration, and other files that must stay synchronized.

# Bind mount — changes are reflected instantly in both directions
docker run -v $(pwd)/data:/app/data my-image