Docker multi-stage build and environment variables
Tags: docker, multistagebuild, envvars, dockercompose
Published: 2020-07-06 23:18:08

---
title: Docker multi-stage build and environment variables
published: true
description: In this post you will learn how to pass variables into build stages in Dockerfiles.
tags: docker, multistagebuild, envvars, dockercompose 
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/77lfh0zhqn3hkqgwq563.jpg
---

This post is just a small compendium of links and ideas I found somewhere else while I was working on the following problem:

> How to pass variables from a docker-compose file into a build stage in the Dockerfile?

## The context

It turns out environment variables can be tricky, there are a few different levels and abstractions for each one of them. For example, if `docker-compose.yaml` builds a service from a `Dockerfile` stage and inside the container we have our own javascript framework with a .env or some defaults, we have the following levels of environment variables:

1. `docker-compose.yaml`
2. `Dockerfile`
3. Container environment files
4. NPM script environment variables
5. Application defaults

If you are like me, it can get messy after a while.

## The flow

First let's get the javascript part out of the way: 

1. **Already existing vars have precedence over .env vars unless you programmatically decide not to**.
2. **NPM script vars take precedence over container environment vars**.

Now, the Docker part. According to the docker-compose file documentation, available [here](https://docs.docker.com/compose/compose-file):

1. [env_file](https://docs.docker.com/compose/compose-file/#env_file) add environment variables from a file.
2. [environment](https://docs.docker.com/compose/compose-file/#environment) add environment variables... but, in the note at the end of the section it mentions that:

> If your service specifies a build option, variables defined in environment are not automatically visible during the build. Use the args sub-option of build to define build-time environment variables.

3. [args](https://docs.docker.com/compose/compose-file/#args) add build arguments, which are environment variables accessible only during the build process.

Well, it is very clear, once you read it. But it is common to assume how things work or to ignore that this document is out there, as you can see from issue [#1837](https://github.com/docker/compose/issues/1837).

At this point we know how to pass a variable from the `docker-compose.yaml` to the `Dockerfile`, but that does not mean that this `ARG` will be available inside of the container. To achieve that we need to assign the ARG to ENV as follows:

```
ARG CONT_IMG_VER
ENV CONT_IMG_VER $CONT_IMG_VER
```

This time the source is the [Dockerfile reference](https://docs.docker.com/engine/reference/builder/#using-arg-variables). There is a catch that is discussed after that section, you have to be aware of the cache miss on the first use of the `ARG`.

As you can see, it is not that hard to get it right, but you need to be aware of a few conventions that are not as intuitive as it might seem. Hope this save you a few minutes.

Finally, here is an interesting post I found while looking for this, [Docker ARG, ENV and .env - a Complete Guide](https://vsupalov.com/docker-arg-env-variable-guide/).

Cover image<span> by <a href="https://unsplash.com/@wanderingkid?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Yohann Mourre</a> on <a href="https://unsplash.com/@wanderingkid?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span>