Dockerfile — COPY vs ADD
You’ve or may have used COPY in every Dockerfile so far without a second thought. There’s a second instruction that does almost the same thing — ADD — and it’s been sitting there the whole time, unused. This is a short one: what ADD does differently, and why COPY was still the right call every single time.
What They Share
Both move files from your build context into the image. For the plain case — a file, going to a path — they’re identical:
COPY index.html .
ADD index.html .Either line produces the exact same layer. If this were the whole story, the instruction wouldn’t need a second name.
What ADD Does Extra
ADD has two tricks COPY doesn’t:
It can fetch a URL directly:
ADD https://example.com/setup.sh /app/setup.shIt auto-extracts local tar archives:
ADD project.tar.gz /app/Copy a .tar.gz with ADD, and it lands in the image already unpacked. COPY would just place the archive file itself, untouched.
Why COPY Wins Anyway
Both extras sound convenient, and both are exactly why ADD is usually the wrong choice:
- The URL fetch skips your build context entirely. Nothing about the download shows up as a file you can inspect beforehand, there’s no checksum, and the request happens fresh on every uncached build. A plain
RUN curlat least makes the download an explicit, visible step —ADDhides it inside an instruction that looks like a simple file copy. - The auto-extraction is a silent behavior change.
ADD some.tar.gz /app/andCOPY some.tar.gz /app/produce genuinely different images, and nothing about readingADDtells you which files a plainCOPYwouldn’t have carried across. That’s a bad kind of surprise for anyone reading the Dockerfile later — including future you.
Note
Docker’s own documentation recommends COPY for anything that’s just moving files, and reserves ADD for the rare case where you specifically want auto-extraction. Not “never use ADD” — just “don’t reach for it out of habit.”
Wrapping Up
COPY does one thing, predictably, every time — that’s the whole appeal. ADD does that same thing plus two extra behaviors that quietly change what ends up in your image, which is exactly why every Dockerfile in this series has used COPY. Default to it, and only reach for ADD when you specifically need a local archive extracted on the way in.