Dockerfile COPY vs ADD: Which to Use

When a Docker image needs application code, configuration, or a release archive, both COPY and ADD can place files in the image. For an ordinary local file, COPY app.py /app/ and ADD app.py /app/ produce the same result, but the instructions differ once archives, remote sources, or build stages are involved.
Use COPY for local files and artifacts from other build stages. Use ADD when you want automatic tar extraction or need BuildKit to fetch a remote HTTP or Git source. This guide compares both instructions and explains which one fits each case.
What COPY Does
COPY takes files or directories from the build context and places them at a destination inside the image:
COPY requirements.txt /app/
COPY src/ /app/src/An archive copied this way stays an archive, and a source path cannot point outside the build context. Two options cover common permission needs by setting ownership and mode as the files are copied:
COPY --chown=appuser:appgroup --chmod=644 config.yml /app/COPY can also read from a named context, another image, or an earlier stage in a multi-stage build. The --from option is commonly used to move compiled artifacts into a smaller production image:
COPY --from=builder /app/target/server /usr/local/bin/serverWhat ADD Does
For local files and directories, ADD behaves much like COPY. It also understands local tar archives, remote URLs, and Git repository sources.
When the source is a local tar archive, either uncompressed or compressed with gzip, bzip2, or xz, ADD extracts it into the destination instead of copying the archive file:
ADD rootfs.tar.gz /Docker detects an archive from its contents, not its filename. A file named rootfs.tar.gz that does not contain a recognized tar archive is copied without an extraction error. When you need the archive itself inside the image, use COPY, or use ADD --unpack=false with Dockerfile syntax 1.17 or later.
For remote sources, ADD can download an HTTP or HTTPS URL. BuildKit supports --checksum so the build fails if the downloaded content does not match the expected SHA-256 digest. Here is a checksum-verified download:
# syntax=docker/dockerfile:1
ADD --checksum=sha256:24454f830cdb571e2c4ad15481119c43b3cafd48dd869a9b2945d1036d1dc68d \
https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/linux-0.01.tar.gz \
/tmp/linux-0.01.tar.gzRemote tar archives are downloaded without extraction by default. Dockerfile syntax 1.17 added --unpack=true for builds that should download and extract a remote tar archive in one instruction.
ADD can also clone a Git repository from an HTTPS or SSH address. A branch, tag, commit, or subdirectory can be selected in the URL, and --checksum can pin a Git source to a commit. These behaviors are covered in the official Dockerfile ADD reference
.
Key Differences
| Source or behavior | COPY | ADD |
|---|---|---|
| Local files and directories | Copies them | Copies them |
| Local tar archive | Keeps the archive | Extracts it by default |
| Remote HTTP or HTTPS URL | Not supported | Downloads it |
| Remote Git repository | Not supported | Clones it |
| Checksum for a remote source | Not applicable | --checksum |
| Remote tar extraction | Not supported | --unpack=true |
| Build stage, named context, or image | --from | Not supported |
Choosing Between COPY and ADD
Use COPY for application source code, configuration, static assets, and other ordinary files from the build context. It states the intent directly and ensures that an archive remains intact. COPY --from is also the correct choice for moving artifacts between build stages or importing files from another image.
Use ADD when its source-aware behavior is part of the task. Local tar extraction is useful for assembling a root filesystem or installing a vendored release archive without storing the compressed archive in its own image layer.
For example, this instruction extracts a local application archive directly into /opt/app/:
ADD app-1.4.2-dist.tar.gz /opt/app/For remote artifacts, current Docker build best practices
favor ADD with --checksum because BuildKit can cache the remote source precisely and verify its contents. A RUN instruction with curl or wget is still appropriate when you need custom request handling or additional processing. Keep verification, extraction, and cleanup in the same RUN instruction so temporary files do not remain in a separate layer.
Conclusion
Choose COPY for local content and multi-stage artifacts. Choose ADD when you need automatic tar extraction or a checksum-verified remote source. For the complete image-building workflow, see our guide on building Docker images with a Dockerfile
, and keep the Docker cheatsheet
nearby for the rest of the instruction set.
Tags
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page