Docker Community Forums

Share and learn in the Docker community.

How to deal with many image building arguments

I have 20-30 variables I need to pass to dockerfile for building an image.
I can see the following options:
#1. use ARGs

  • easy to set defaults as ARG param=default_value
  • easy to pass non-default values as --build-arg


  • each ARG is processed creating and removing an intermediate container, what at least takes time
  • each ARG should be specified again after each FROM, need to declare many duplicated ARGs, cannot set one global ARG.

#2. use ENV

  • faster, all ENVs can be set once and not processed via intermediate container for each of them


  • not obvious how and where to set defaults, not as easy as in case of ARGs
  • in order to to pass non-default values I would need to set environment variables before calling build, instead of passing --build-arg
  • all the env variables will exist in the image and whereas they only needed on the building stage

#3. build docker file on fly from a template by a shell script, replacing parameters on the values there

  • faster, no need to declare duplicate ARGs


  • extra logic, complicates the process

Am I missing anything?

What option would you prefer?

I am kind of confused about the variations.

I allways follow a simple pattern:
– ARG: whenever a variable is used for build-time commands
– ENV: whenever a variable is used for run-time commands, either directly understood by the main application or used in entrypoint scripts to modify configuration files before the main application is started.

Usualy people tend to put everything into ENV variables, which makes end users of the image wonder why a modification of some of the ENV variables has no effect.

I prefer to not use conditional steps in Dockerfiles. Instead I create different Dockerfiles, as ultimately the resulting image is not the same.

I am kind of confused about the variations.

In case I was not clear let me clarify.
Imagine we have 20 parameters used for building an image, which
.1. have defaults
.2. we should be able to pass non-default values easy

ARGs work for this goal, e.g. it would look like this
ARG param1=default1
ARG param2=default2

ARG param10=default10

Here we have default values, and can pass specific non-default values by “–build-arg” parameters.
The cons of using ARGs are
.1. we have to re-define them after each FROM
.2. they create an intermediate containers for each ARG
so with 10 ARGs and 3 FROMs it would be 40 ARGs, which make the process slower due to creating/removing intermediate containers

It would be faster with ENVs, but in order to set the defaults we would need to add an extra script called before the docker file to set env variables with default values for those which are not set yet,
it could be something like this
export param1= {param1:-default} export param2= {param2:-default}
export param10= ${param10:-default}

ENV param1=$param1


In this case we would set non-default parameters as environment variables before calling and then calling docker build with our docker file.

Option #3 is where we create a specific docker file for each image, replacing the variables by the values, so the docker file would not have ARGs at all, but had actual values, like
docker file:
COPY somefile1 somefile2 /home/username/

instead of
COPY $param1 $param2 $param3
which we have with using ARGs

I wasn’t confused because I didn’t understand you… I was confused about why you strip away the semantics of ARGs and ENVs.

So basicly you have two options, not three. Either use ARGs and ENVs how they are supposed to be used, or render the Dockerfile to skip ARGs completly and render their values staticly into the file. A simple templating can be achived with envsubst of the gettext package. You will not get any oprhaned intermediate containers, if you append the parameter --force-rm.

Without seeing your Dockerfile, it is impossible to spot design problems in you Dockerfile. Using 20-30 Args kind of smells like a non optimal design…