Why are my Docker ARGs empty?

If you're running into issues with your Docker ARGs not setting correctly in your Dockerfile, it may be because of where they're placed. Consider this example Dockerfile:

ARG VERSION=latest
ARG FILENAME

FROM ubuntu:${VERSION}

COPY ${FILENAME} /home/ubuntu/${FILENAME}

Say you try and build this with docker build . --tag myimage:latest --build-arg VERSION=18.04 --build-arg FILENAME=foo.txt. You might be surprised if foo.txt isn't copied to your container

The reason for this is that every FROM in your Dockerfile creates a new build stage, which causes values of any ARG from previous stages to be lost. The correct syntax for the above Dockerfile is:

ARG VERSION=latest

FROM ubuntu:${VERSION}

ARG FILENAME
COPY ${FILENAME} /home/ubuntu/${FILENAME}

But what if you want to have your VERSION argument available later on in the build process? Luckily, the documentation provides the answer—redeclare an empty argument after the FROM statement (i.e. within the next build stage):

ARG VERSION=latest

FROM ubuntu:${VERSION}

ARG VERSION
ARG FILENAME
COPY ${FILENAME} /home/ubuntu/${FILENAME}

So there you go—mystery solved. As long as you're mindful of when each build stage starts, it's a simple matter to make sure you have access to the right ARGs in the right places.