Docker Tip #47: Build Time vs Run Time ENV Variables

Docker allows you to set both build time and run time ENV variables and even lets you overwrite build time ENV vars at run time.
There may come a time where you’ll want to add an ENV variable to your Docker
image, but you’ll want this value to be different depending on where you build
your image, but you don’t want to edit your Dockerfile to change it.
You may also want to sometimes overwrite that value at run time (not build time).
Setting up a Docker image with a build argument and ENV variable:
FROM debian:stable-slim
ARG YOURAPP_ENV=production
ENV YOURAPP_ENV="${YOURAPP_ENV}"
YOURAPP_ENV could be RAILS_ENV, NODE_ENV or whatever environment
variable you want to set at build time.
The ARG and ENV variable names don’t need to match, but it’s generally a
good idea to keep them the same for consistency. In this case, the ENV variable
will default to whatever the ARG is set to at build time (or “production” if
none is supplied).
A few outcomes when building and running the above Docker image:
# A typical build.
docker build -t yourapp .
docker run --rm yourapp env | grep YOURAPP_ENV
> YOURAPP_ENV=production
# Building it with a custom --build-arg value.
docker build -t yourapp --build-arg YOURAPP_ENV=staging .
docker run --rm yourapp env | grep YOURAPP_ENV
> YOURAPP_ENV=staging
# Overwriting the ENV's value at run time instead of build time.
docker run --rm -e YOURAPP_ENV=development yourapp env | grep YOURAPP_ENV
> YOURAPP_ENV=development
If you’re using Docker Compose instead, it supports both setting build arguments and also setting environment variables at run time, so this all works the same way.
A quick Docker Compose example that sets a build argument:
services:
yourapp:
build:
context: "."
args:
YOURAPP_ENV: "helloworld"
Now if you run docker-compose up --build and took a look at the environment
variables in the container you would see YOURAPP_ENV=helloworld.
You could even define that arg as a variable with ${YOURAPP_ENV:-helloworld}
and if you have it defined in a .env file then Docker Compose will pick it up
automatically. If it’s not defined it’ll fall back to the default value of
helloworld.
Also, if you set YOURAPP_ENV as an environment variable in the
docker-compose.yml file with the environment property (or being loaded in
from a file with env_file) it would overwrite the build argument just like it
did without Docker Compose. Feel free to try that out on your own!