When creating a Dockerfile, there are two commands that you can use to copy files/directories into it –
COPY. Although there are slight differences in the scope of their function, they essentially perform the same task.
So, why do we have two commands, and how do we know when to use one or the other?
In this article, we explain each command, analyze Docker ADD vs COPY, and tell you which one to use.
Docker ADD Command
Let’s start by noting that the
ADD command is older than
COPY. Since the launch of the Docker platform, the
ADD instruction has been part of its list of commands.
The command copies files/directories to a file system of the specified container.
The basic syntax for the
ADD command is:
ADD <src> … <dest>
It includes the source you want to copy (
<src>) followed by the destination where you want to store it (
<dest>). If the source is a directory,
ADD copies everything inside of it (including file system metadata).
For instance, if the file is locally available and you want to add it to the directory of an image, you type:
ADD /source/file/path /destination/path
ADD can also copy files from a URL. It can download an external file and copy it to the wanted destination. For example:
ADD http://source.file/url /destination/path
An additional feature is that it copies compressed files, automatically extracting the content in the given destination. This feature only applies to locally stored compressed files/directories.
Type in the source and where you want the command to extract the content as follows:
ADD source.file.tar.gz /temp
Bear in mind that you cannot download and extract a compressed file/directory from a URL. The command does not unpack external packages when copying them to the local filesystem.
Note: The ADD command extracts a compressed source only if it is in a recognized compression format which is solely based on the contents of the file (not on the file name). The recognized compression formats include identity, gzip, bzip, and xz.
Docker Copy Command
Due to some functionality issues, Docker had to introduce an additional command for duplicating content –
Unlike its closely related
COPY only has only one assigned function. Its role is to duplicate files/directories in a specified location in their existing format. This means that it doesn’t deal with extracting a compressed file, but rather copies it as-is.
The instruction can be used only for locally stored files. Therefore, you cannot use it with URLs to copy external files to your container.
To use the
COPY instruction, follow the basic command format:
COPY <src> … <dest>
COPY /source/file/path /destination/path
Docker Copy vs ADD
Why was there a need to add a new, similar command?
The fact that
ADD had so many functionalities proved to be problematic in practice, as it behaved extremely unpredictable. The result of such unreliable performance often came down to copying when you wanted to extract and extracting when you wanted to copy.
Docker couldn’t completely replace the command due to its many existing usages. To avoid backward compatibility, the safest option was to add the
COPY command – a less diverse yet more reliable command.
Which to Use (Best Practices)
Considering the circumstances in which the
COPY command was introduced, it is evident that keeping ADD was a matter of necessity. Docker released an official document outlining best practices for writing Dockerfiles, which explicitly advises against using the
Docker’s official documentation notes that
COPY should always be the go-to instruction as it is more transparent than
If you need to copy from the local build context into a container, stick to using
The Docker team also strongly discourages using
ADD to download and copy a package from a URL. Instead, it’s safer and more efficient to use wget or curl within a
RUN command. By doing so, you avoid creating an additional image layer and save space.
Let’s say you want to download a compressed package from a URL, extract the content, and clean up the archive.
Instead of using
ADD and running the following command:
ADD http://source.file/package.file.tar.gz /temp RUN tar -xjf /temp/package.file.tar.gz \ && make -C /tmp/package.file \ && rm /tmp/ package.file.tar.gz
You should use:
RUN curl http://source.file/package.file.tar.gz \ | tar -xjC /tmp/ package.file.tar.gz \ && make -C /tmp/ package.file.tar.gz
Note: The only time you would need to use the ADD command is when extracting local tar files into the image.
To sum up – use COPY. As Docker itself suggests, avoid the ADD command unless you need to extract a local tar file.
To learn more about creating Dockerfiles check out this article on How to Create Docker Images With Dockerfile.