Going to AWS re:Invent 2024?

➡️ Book a meeting with Spacelift

Docker

What are Docker Build Args & How to Use Them [Tutorial]

docker build args

Docker build arguments let you set build-time variables that you can reference in your Dockerfile instructions. They make the Docker image build process configurable at build time.

In this article, we’ll explore how build args work and discuss the ways in which you can use them. Let’s begin!

  1. What are Docker build args?
  2. Using Docker build args: ARG and –build-arg
  3. When to use Docker build args?
  4. Docker build args vs environment variables (ARG vs ENV)
  5. Docker build args limitations

What are Docker build args?

Docker build args (build arguments) are variables that you can use in your Dockerfile. They don’t affect the image’s content on their own, but they allow you to template your Dockerfile so you can change how each build is performed. 

Docker build arguments are defined in the Dockerfile and can be set or overridden during the build process using the --build-arg flag. 

Build args are essentially environment variables that exist only during the image-building phase.  They’re not saved in the Docker image and can’t be accessed by running containers. To pass values into containers, environment variables must be used instead.

Using Docker build args: ARG and --build-arg

Build args are defined by the Dockerfile ARG instruction. Once a variable has been defined, later Dockerfile instructions can reference its value:

ARG IMAGE_VERSION=3
FROM alpine:${IMAGE_VERSION}

Build argument values are populated at build-time via the docker build command --build-arg flag:

$ docker build --build-arg IMAGE_VERSION=latest -t example:latest .

This example causes the image to be built from the alpine:latest base image, instead of the default value of alpine:3.

The --build-arg flag can only set build args that are actually defined in your Dockerfile. Specifying build args with no matching ARG instruction won’t affect your build.

Using multiple build args

You can define multiple build args by repeating the ARG instruction in your Dockerfile:

ARG foo
ARG bar

Each ARG allows you to pass different variables during the build process.

The --build-arg build flag must then be repeated for each argument you want to set:

$ docker build --build-arg foo=example --build-arg bar=demo -t example:latest .

Populating build args from shell environment variables

You can use the --build-arg flag without specifying a value for the arg. This will automatically look for a shell environment variable with the same name as the build arg and propagate the environment value into your build.

$ export MY_VAR=demo

# $MY_VAR is "demo" inside the build 
$ docker build --build-arg MY_VAR -t example:latest .

This is a useful way to avoid hardcoding build arg values in scripts that call docker build.

Making build args required

Docker always treats build args as optional. No error is thrown if you run docker build command without a --build-arg flag for one of your ARG instructions. The following table summarizes the behavior:

ARG instruction --build-arg value Final value
ARG foo Not Set Empty
ARG foo --build-arg foo=bar bar
ARG foo=bar Not Set bar
ARG foo=bar --build-arg foo=demo demo

If you’d like a build arg to require input, you can run the shell test command during the build. Docker will interpolate the arg’s value into the command; test then checks the input and exits with an error code if it’s empty. This will cause the build to fail.

ARG DEMO_VARIABLE

# build fails if there’s no --build-arg DEMO_VARIABLE flag
RUN test -n "${DEMO_VARIABLE}"

Using built-in build args

Docker includes a small set of predefined build args you can use without adding an ARG instruction to your Dockerfile. These are currently:

  • HTTP_PROXY
  • HTTPS_PROXY
  • FTP_PROXY
  • NO_PROXY
  • ALL_PROXY
  • Lowercase variants of all of the above.

You can always set values for these build args using --build-arg.

The BuildKit build engine provides some additional predefined build args, which let you customize how BuildKit runs the build.

BuildKit also exposes access to certain build environment details via the following pre-populated build args:

  • BUILDPLATFORM
  • BUILDOS
  • BUILDARCH
  • BUILDVARIANT
  • TARGETPLATFORM
  • TARGETOS
  • TARGETARCH
  • TARGETVARIANT

You can access these build args by simply naming them in an ARG instruction. There’s no need to set the --build-arg flag:

ARG TARGETARCH

RUN curl https://example.com/my-binary-v1-${TARGETARCH}.tar

When to use Docker build args?

Build args eliminate hardcoding of Dockerfile values that users might have to change before a build. They also let you build many image variations from a single Dockerfile. This makes it easier to maintain your build configurations.

Common build arg use cases include:

  • Setting version numbers or labels
  • Changing the base image tag that you build from allows you to build both node:20-bookworm (Debian) and node:20-alpine (Alpine) flavors of your image.
  • Customizing which app features an image includes, such as by only COPY-ing a certain component into the image if a specific build arg is set.
  • Setting default container environment variables — for example, you could use build args to populate BUILD_SHA and BUILD_TIME environment variables that your app can display.

Build args shouldn’t be used with secret values such as API tokens and credentials. Although build args aren’t visible inside containers, they’re part of the image’s metadata and can be retrieved with the docker history command. Use Docker’s build secrets mechanism to protect sensitive values and prevent them from being exposed to image users.

Docker build args vs. environment variables (ARG vs. ENV)

In Docker build, both build arguments (build args) and environment variables serve to configure the behavior of images and containers. Build args are for configuring what happens during docker build, whereas environment variables (env variables) are values set inside running containers.

  • Use a build arg if the value will be used by your Dockerfile instructions and doesn’t need to be saved in the image.
  • Use an environment variable to set container values that can be read by your app.

It’s possible to use build args and environment variables together. This pattern allows build authors to set default values for environment variables:

FROM alpine:3
ARG NEW_FEATURE_ENABLED=0
ENV NEW_FEATURE_ENABLED=${NEW_FEATURE_ENABLED}

This Dockerfile defines a build arg called NEW_FEATURE_ENABLED and then assigns its value to an environment variable with the same name. The value of NEW_FEATURE_ENABLED inside the container will now match the value passed as --build-arg NEW_FEATURE_ENABLED during the image build:

$ docker build --build-arg NEW_FEATURE_ENABLED=1 -t example:latest .

# prints "1"
$ docker run --rm example:latest sh -c 'echo $NEW_FEATURE_ENABLED'

If the ENV instruction was removed from the Dockerfile the variable wouldn’t be set inside the container.

Container creators can still change the container variable’s value via the docker run command’s -e/--env flag:

# prints "0"
$ docker run --rm --env NEW_FEATURE_ENABLED=0 example:latest sh -c 'echo $NEW_FEATURE_ENABLED'

Docker build args limitations

Build args have a few limitations to bear in mind. The first is simple: build args can only be used by the Dockerfile instructions that follow their definition. If you try to access a build arg before it’s defined, an empty string will always be returned:

# prints nothing
RUN echo ${foo}

ARG foo=bar

# prints bar
RUN echo ${foo}

Build args are also discarded at the end of each build stage. When you’re writing a multi-stage Dockerfile, you must include the ARG instruction in every stage that needs a particular build arg.

FROM node:latest AS node
RUN npm install
ARG BUILD_VERSION
RUN echo $BUILD_VERSION > version.txt

FROM httpd:alpine AS httpd
ARG BUILD_VERSION
RUN echo $BUILD_VERSION > version.txt

If the second ARG instruction was removed from this Dockerfile, the final RUN statement wouldn’t have the expected result. The first ARG instruction only applies to the stage that it’s defined in. This differs from the behavior of ENV instructions.

Additionally, build args can only be referenced by Dockerfile instructions that support variable interpolation. These are:

  • ADD
  • COPY
  • ENV
  • EXPOSE
  • FROM
  • LABEL
  • STOPSIGGNAL
  • USER
  • VOLUME
  • WORKDIR
  • ONBUILD

Build arg references won’t be expanded when used in any other instruction.

Key points

We’ve explored Docker build arguments, a powerful mechanism for making your Docker image builds more customizable. Now you can easily create configurable builds that let you produce different image variants from a single Dockerfile.

Combine build args and environment variables to inject default container values at build-time. Just remember that build args won’t be automatically persisted in your image, until they’re manually assigned to an environment variable by an ENV instruction.

Ready to learn more techniques for improving your Docker image builds? Find more best practices in our guide to writing a Dockerfile.

We also encourage you to explore the ways Spacelift offers full flexibility when it comes to customizing your workflow. You can bring your own Docker image and use it as a runner to speed up deployments that leverage third-party tools. Spacelift’s official runner image can be found here.

If you want to learn more about what you can do with Spacelift, check out this article, create a free account today, or book a demo with one of our engineers.

Solve your infrastructure challenges

Spacelift is a flexible orchestration solution for IaC development. It delivers enhanced collaboration, automation, and controls to simplify and accelerate the provisioning of cloud-based infrastructures.

Learn more

The Practitioner’s Guide to Scaling Infrastructure as Code

Transform your IaC management to scale

securely, efficiently, and productively

into the future.

ebook global banner
Share your data and download the guide