Docker COPY: Dockerfile best practices

Docker has two similar Dockerfile instructions, COPY and ADD, which are both used to include files in an image. This article will explain why it is best practice to use COPY rather than ADD, unless you want to auto-extract a local tar file into an image.

Best practices for using COPY

This Dockerfile instruction copies one or many local files or folders into the destination within your Docker image.

  • COPY <source>... <destination>
  • COPY ["<source>",... "<destination>"] (this form is required for paths containing whitespace)

An example Dockerfile that uses COPY

This is how you would use COPY in a Dockerfile for a Ruby app.

FROM ruby:2.5.1
WORKDIR /usr/src/app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
CMD ["./your-daemon-or-script.rb"]

It builds up the image in layers, starting with the parent image ruby:2.5.1, defined using FROM.

The Docker instruction WORKDIR defines a working directory for the COPY or ADDs instructions that follow it.

When you use COPY it will copy the files from the local source, in this case . meaning the files in the current directory, to the location defined by WORKDIR. In the above example, the second . refers to the current directory in the working directory within the image.

Best practices for creating image layers with COPY

Docker recommends using COPY to create image layers in a way that keeps different file contexts in separate image layers. This means rebuilding the image is efficient. The files least likely to be changed should be in lower layers, while the files most likely to change should be added last.

If you have multiple Dockerfile steps that use different files from your context, COPY them individually, rather than all at once. This ensures that each step’s build cache is only invalidated (forcing the step to be re-run) if the specifically required files change.
 — Best practices for writing Dockerfiles

This principle is demonstrated in the Dockerfile example above. By copying the Gemfiles followed by RUN bundle install , an image layer is created with the installed Ruby Gems, which can be cached. The last two Docker instructions copy the app’s files into the image and set the default command using CMD.

This means if you change any of the app’s files, you can rebuild the Docker image using the cached parent and intermediate layers. This is much more efficient than building all of them from scratch.

Why you should not use ADD

The ADD instruction has similar syntax to COPY. As well as copying local files and directories into the destination within the Docker image, it has some additional features.

  • ADD <source>... <destination>
  • ADD ["<source>",... "<destination>"] (this form is required for paths containing whitespace)

However, Docker’s official guide to Dockerfile best practices states that COPY is the preferred instruction over ADD in most uses.

Although ADD and COPY are functionally similar, generally speaking, COPY is preferred. That’s because it’s more transparent than ADD. COPY only supports the basic copying of local files into the container, while ADD has some features (like local-only tar extraction and remote URL support) that are not immediately obvious. Consequently, the best use for ADD is local tar file auto-extraction into the image, as in ADD rootfs.tar.xz /
Best practices for writing Dockerfiles

One of ADD‘s additional features is that it can copy files from a URL, but Docker advises against using it for this purpose.

Best practices for copying files from a URL

If ADD’s source is a URL, it will download and copy the file into the destination within the Docker image. Docker suggests that it is often not efficient to copy from a URL using ADD, and it is best practice to use other strategies to include the required remote files.

Because image size matters, using ADD to fetch packages from remote URLs is strongly discouraged; you should use curl or wget instead. That way you can delete the files you no longer need after they’ve been extracted and you don’t have to add another layer in your image. 
 — Dockerfile Best Practices

For example, you should avoid doing things like:

ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all

And instead, do something like:

RUN mkdir -p /usr/src/things \
&& curl -SL http://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all

When you could use ADD

If <source> is a local tar archive in a recognized compression format, then it is automatically unpacked as a directory into the Docker image. For example: ADD rootfs.tar.xz /. This is the main recommended use of ADD over COPY in Dockerfiles.

For other items (files, directories) that do not require ADD’s tar auto-extraction capability, you should always use COPY.

Find out more

The official Dockerfile reference goes into further detail on COPY, ADD and other Dockerfile instructions.

When writing your Dockerfiles, Docker’s Best practices for writing Dockerfiles covers many more tips for how to structure your Dockerfiles, images, and containers efficiently.

Recommended books

I own and have found the following books helpful when learning Docker, containerisation, and shell commands. These contain Amazon affiliate links. If you click through & make a purchase, I will earn a commission at no additional cost to you.

Read more from ryanwhocodes