docker cp — copy files between container and host
Quick Answer
# 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
Usage
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.
Command model
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
Source and destination
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.
- Use
container:/path/directorywhen the directory itself is the artifact. - Use
container:/path/directory/.when only its children should be merged into an existing host directory. - Inspect both sides with
ls -labefore retrying a command that created an unexpected nested directory.
Ownership and permissions
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
Verify the copy
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
Choose the right mechanism
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.
Other causes & fixes
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
Related