The Guide to Docker ARG, ENV and .env
4 min read

The Guide to Docker ARG, ENV and .env

The Guide to Docker ARG, ENV and .env

For those in a hurry, here’s a table summarizing the content of this post. You can find a higher resolution here.

The TL;DR table

Why this guide?

Many times, developers have been left scratching their heads figuring out the best way to pass in variables at different stages of development and deployment. I, myself, are guilty of that. To solve this once and for all, I decided to experiment and note down my observations in this article. 🤗

Setting Environment Variable in Docker

In this section, I present you with four different ways you can provide values to the environment variables to your docker image during build-time using docker-compose.

1. Docker Dot-Env File (.env)

The .env file is probably the most common way to set the environment variables. By storing the variables in a file, you can track their changes using Git. Typically, the content of .env is written in the follow notation:

With the .env file in the current directory and the following docker-compose.yml file, you can run the command docker-compose up -d to spin up a container. Behind the scenes, it will read the variables in .env file and print the value to console as instructed by command. To verify, run docker logs ubuntu and you will see the variable ONE being logged.

Fun fact: the double $$ is used if you need a literal dollar sign in a docker-compose file. This also prevents Compose from interpolating a value, so a $$ allows you to refer to environment variables that you don’t want processed by Compose. This is documented here.

2. Using host’s environment variable

Alternatively, if you do not wish to create a .env file, and instead want to use an existing environment variable in your host, you can also do so with the following docker-compose.yml file. This way, Docker will read in your host’s environment variable and pass it to the container. However, I do not recommend using this method as it may make it hard for you to debug.

3. Docker ENV

Another way of setting environment variables is to define it directly in your docker-compose.yml file using the environment: syntax.

4. Using Shell Parameter Expansion

The last way is to set the environment variable within the parameter itself. Using the Shell Parameter Expansion feature, ${VARIABLE_ONE:-ONE} would default to the value ONE if it is not overridden during run-time. For more information about this behavior, see bash reference and the documentation by Docker here.

Two types of variables in Docker — ARG and ENV

There are two types of environment variables in Docker. In a Dockerfile, they come in the syntax of ARG and ENV. In a Docker Compose file, they are args: and environment:. I have summarized the differences below in point-form for easy reference.

ENV

  • ENV are available during build-time and run-time
  • Use this to pass in secrets during run-time and avoid hard-coding them in build-time
  • ENV cannot be declared before the FROM syntax
  • In a multi-stage build, ENV persists across all stages
  • Takes precedence over ARG of the same variable name. For example, in a Dockerfile where the same variable name is defined by both ENV and ARG, the value for ENV will be used instead of ARG

ARG

  • ARG are also known as build-time environment variables as they are only available during build-time, and not during run-time
  • Do not use this to set secrets because build-time values are visible to any user of the image using the docker history command
  • ARG can be declared before the FROM syntax
  • In a multi-stage build, ARG does not persist beyond the first stage
  • During build-time, you can override the ARG variables with the flag --build-arg <varname>=<value> to build image with different variables. Note: this does not work if there exists ENV configured with the same variable name, see section below on precedence

ENV takes precedence over ARG

In the following example, the same variable SOME_VAR is defined by both ARG and ENV. As the value from ENV takes precedence over ARG, building the image using the command docker build --no-cache -t demo . would print Build-time: SOME_VAR is set to env-value in one of the layers as it prints value from the ENV instead. This means that value from ARG is ignored.

Also, building the image with the flag --build-arg SOME_VAR=new-value will have no effect as well.

Multi-Stage Image Build with ONBUILD syntax

The concept of ONBUILD allows you to declare ARG and ENV in a stage and let the values be available only in the subsequent stages.

In the Dockerfile example below, I’ve declared four environment variables in the first stage, namely VAR_ENV, VAR_ARG, VAR_ENV_ONBUILD and VAR_ARG_ONBUILD.

During build-time, notice that in Step 6 (first stage), only VAR_ARG and VAR_ENV are printed. However, in Step 8 (second stage), VAR_ARG_ONBUILD, VAR_ENV_ONBUILD and VAR_ENV are printed except VAR_ARG. This proves that VAR_ARG does not persist beyond its own first stage and that VAR_*_ONBUILD are only available in subsequent second and third stages (see Step 10 for third stage).


Optional Read: Background on Environment Variable vs Shell Variable

In case you are wondering, a Shell Variable is local to a particular instance of the shell, while the Environment Variables are inherited by any program, including from another shell session. This also means that a Shell Variable is a subset of Environment Variables, and is “temporarily” available to the shell session in a sense.

In general, the variables are stored in a key-value pair structure. Shell Variable is set using the command SOME_SHELL_VAR=shell-var and Environment Variable is set using export SOME_ENV_VAR=env-var, with the extra export keyword. There are a few ways to list all the currently defined environment variables and that is by running the command set, printenv or env. However, the shell variables (non-exported) can only be found using the set command.

View all Shell and Environment Variables using set

Setting and viewing a Shell Variable

View all Environment Variables using printenv

Setting and viewing an Environment Variable

For more detailed information, see the guide from Ubuntu here.


Conclusion

By now you should have a good understanding of how environment variables work in Docker — in both forms of ENV and ARG. I hope this serves as a good reference to in your journey to learning and using Docker. 🤗