How to Use Docker Build Args to Configure Image Builds

Docker’s “build args” mechanism lets you define environment variables that can be referenced in your Dockerfile during image builds. Unlike regular ENV instructions, build args are not present inside the final output image. They’re for cases where you want to configure the build process instead of created containers.

Defining Build Args

You define build args inside your Dockerfile using ARG instructions:

ARG EXAMPLE_VAR
ARG DEMO_VAR

RUN echo $EXAMPLE_VAR

Two arguments, EXAMPLE_VAR and DEMO_VAR, are added to the build by the Dockerfile above.

You set the values of available arguments via the --build-arg flag for docker build. Repeat the flag multiple times to cover all the arguments defined in your Dockerfile:

docker build -t example-image:latest 
    --build-arg EXAMPLE_VAR=value1 
    --build-arg DEMO_VAR=value2 
    .

Building the sample Dockerfile using this command will emit value1 to your terminal during the build. The EXAMPLE_VAR variable is made available in the build environment with the value value1. The value component of the --build-arg flag is optional; omitting it will automatically select the value of the variable in your local shell environment.

As build args aren’t persisted to the built image, you’ll see an empty string when running echo $EXAMPLE_VAR inside containers created from example-image:latest. Variables which running containers need to reference should be added using ENV instructions and --env or -e build flags.

Although they’re not in the final image, build args still impact Docker’s build cache. Changing an arg’s value between builds can cause cache misses for instructions that follow the first reference to the variable. The defining ARG statement is not responsible for the cache invalidation.

FROM alpine:latest
ARG EXAMPLE_VAR

# Cache is not invalidated - arg hasn't been used
RUN example-command

# Build cache can't be used from this point onwards
RUN echo $EXAMPLE_VAR

Default Build Arg Values

The ARG instruction can be given a default value to use when no matching --build-arg flag is supplied:

ARG EXAMPLE_VAR=demo

Docker will always prefer the value given by the --build-arg flag when one is available. If it’s missing, EXAMPLE_VAR will be set to demo within the build environment. This reduces the number of flags you need to supply when building an image with arguments that are rarely overridden.

Where Can Build Args Be Used?

Build args can be referenced in the Dockerfile instructions that follow them. They work with most kinds of instruction including RUN commands executed in the intermediary build containers. Arguments are referenced in the same way as environment variables, using the $EXAMPLE_VAR syntax.

ARG instructions are unique as they materially affect the build but can be used before FROM statements. It’s permitted to reference build args inside a FROM instruction, letting you select a different base image depending on the user’s configuration:

ARG BASE_IMAGE_VERSION=alpine
FROM my-app-base:2-${BASE_IMAGE_VERSION}
docker build -t my-app:latest --build-arg BASE_IMAGE_VERSION=debian .

Build args are available from the line on which they’re defined. Any following instruction can reference the value of build args created above it in the Dockerfile. You must add ARG instructions for all the build args you’ll use. Referencing an argument before it’s been defined – or using a --build-arg with no corresponding ARG – will result in an empty string.

Build args don’t work across build stages. Each stage acts as a new build with its own set of build arguments. ARG instructions included in previous stages have no effect on later ones unless they’re repeated within each stage:

FROM php:latest
ARG BUILD_VERSION

FROM composer:latest
ARG BUILD_VERSION

Both stages explicitly define the BUILD_VERSION arg so the value set with --build-arg will be supplied to each one.

Build stage considerations also apply when you’re using ARG before a FROM instruction. These arguments exist outside of any build stage; they’re shared by all FROM statements but can’t be referenced by following instructions. If you want to reuse a FROM-level build arg inside a stage, repeat the ARG instruction to pull in its value:

# Only applies to FROM instructions
ARG BASE_IMAGE_VERSION=alpine
FROM my-app-base:2-${BASE_IMAGE_VERSION}

# Reference the outer build argument
ARG BASE_IMAGE_VERSION

# Works as expected
RUN echo $BASE_IMAGE_VERSION

These special concerns aside, arguments behave similarly to environment variables in all other respects. You can override their values using ARG and ENV instructions, interpolate them into strings, and use them in expansion expressions of the form ${EXAMPLE_VAR:-demo}. This selects demo as the value when the EXAMPLE_VAR variable isn’t set.

Predefined Build Args

Docker supports some build arguments by default, even if you don’t include their ARG instructions in your Dockerfile. They relate to proxy settings and work whenever their corresponding --build-arg flag is used. The variables are also excluded from docker history output to avoid disclosing the potentially sensitive details they’re intended for – more on this command and its implications below.

Builds handled by the BuildKit backend can access several other predefined build args too. These are supplied with automatically injected values. The list includes TARGETOS, TARGETARCH, TARGETPLATFORM, and BUILDOS, BUILDARCH, and BUILDPLATFORM, among several others. The variables describe characteristics of the build environment and the platform the new image is targeting.

When To Use Build Args?

Build args can be used to inject configuration into Docker image builds. They’re a way to dynamically modify the final image without writing multiple Dockerfiles.

You can use this mechanism to modify a build’s base image, change the commands that are executed by RUN instructions, and provide user-changeable settings that expose image customization options. Build args make sense for most values which are only used during the build process and which you don’t want hardcoded into your Dockerfile.

There are some situations where alternative approaches should be used. While convenient, build args aren’t ideal for secret data such as authentication tokens and keys. Because ARG is a Dockerfile instruction, variables and their values are visible when inspecting an image with the docker history command. Anyone with access to your image can therefore view the keys used during the build.

Credentials used to authenticate your build process to package registries and source control repos are best supplied as BuildKit build secrets. These are designed to handle sensitive information and are mounted as files into the build environment, instead of becoming image instructions.

Summary

Build args let you configure Docker image builds using a combination of Dockerfile instructions and command-line arguments at build time. Unlike environment variables, build args aren’t accessible to running containers, although they’re still visible in the image’s layer history.

A build arg is the right choice for non-sensitive user-customizable settings that affect your build process. Use an environment variable instead when you want to expose the value in the final image. BuildKit secrets are a better third option for any valuable data that your build needs to access.

You may also like...