Copy is a copying operation that copies the contents of one file to another. It is the most common way to copy files in Dockerfiles. ADD is an addition operation that adds new files to a container. ADD works best when there are many files to add, as it can take a while for the container to find and add them all.


ADD and COPY are two similar Dockerfile instructions which let you add content to your images at build time. Whereas COPY is a straightforward source to destination copy, ADD includes extra functionality for working with archives and remote URLs.

COPY

COPY is the simpler of the two instructions. It accepts two arguments, a source and destination:

The source path will be copied from your Docker host into the container’s filesystem. The built image will include the copied file or directory at the specified destination path.

COPY works with all files and directories but source paths are restricted to those within your active build context. The context is set when you run docker build:

The instruction automatically creates the destination directory in the container when it doesn’t already exist. If you include a trailing slash (/), Docker treats the destination as a directory and will place the source file inside it.

You can use wildcards such as *.jpg in the source path destination to match a set of files. These expressions will be parsed using the Go filepath matcher.

Copied files have a UID and GID of 0 by default. This can be customized with the optional –chown flag which accepts UIDs, GIDs, and names. It runs chown on the copied files once they’re inside the container:

COPY also supports a –from flag. This modifies the source path to refer to another container image, instead of your local build context. It also works with multi-stage builds to pull in artifacts created by earlier build stages.

The –from flag must refer to a named stage that’s listed earlier in the Dockerfile. When there’s no matching stage, Docker assumes you’re referencing an image instead. You’ll hit a build error if the image can’t be pulled.

ADD

ADD has the same syntax as COPY, accepting source and destination paths. There’s no support for –from but you can use –chown.

Unlike COPY, ADD is capable of downloading remote file URLs. Specifying a publicly accessible URL as the source path will download that file and add it to the container image. The destination path’s modified time (mtime) will be set to the value of the Last-Modified header in the download’s HTTP response.

ADD can also extract tar archives, including archives compressed with gzip, bzip2, and xz. Specifying a compatible archive as the source path will unpack its contents into the specified container directory. The existing contents of the directory will be retained.

Archive detection is based on the actual file contents, not the filename or extension. You can use any genuine archive file without naming it .tar, .tar.gz or .tar.xz.

The ability to automatically extract archives simplifies adding software packages distributed as tar files to your container images. Supplying a tar path to COPY would copy the compressed archive file as-is, not its contents. You’d need to use a RUN instruction to manually decompress the file.

The behaviors around COPY apply to ADD to. Except for remote URLs, source paths must exist in your build context. The container’s destination path will be automatically created when it doesn’t exist using Docker’s rules for path resolution.

Summary

COPY and ADD are two closely related but distinctly different instructions you can use when writing a Dockerfile. As their feature sets overlap, you might be wondering which is the “best” to use by default.

According to Docker’s own best practices guide, you should reach for COPY unless you need the extra capabilities of ADD. ADD is an opaque operation that adds magic to the copying process.

Only using ADD when it’s actually needed helps to communicate your intentions. Otherwise, you risk getting team members into the habit of using ADD which could have disastrous consequences. An unintentional ADD my-archive.tar . instead of COPY my-archive.tar could cause confusion and broken builds when the archive’s contents show up in your container, instead of the archive itself.

You should also carefully consider when it’s appropriate to use ADD with remote URLs. It can be more efficient to use curl or wget with a RUN instruction as this helps facilitate image layer caching. An ADD instruction will always invalidate the cache for all following build stages when the file at a remote URL changes.

Where possible, it’s good practice to delete copied files after they’ve been used. If you’re downloading or extracting a software installer, deleting the one-time binary after you’ve run it will help to slim down your final image.