Set docker build args from .env file (NextJS)
Robin Kretzschmar

Robin Kretzschmar @darksmile92

About: Started coding at the age of 13, now a professional software engineer and Scrum Master, creating and maintaining enterprise solutions. Eat - Sleep - Code - Lift - Repeat 💪🏾

Location:
Mannheim, Germany
Joined:
Nov 14, 2017

Set docker build args from .env file (NextJS)

Publish Date: Sep 15 '22
31 6

I recently came across the issue that I had to build a Docker container with a NextJS app inside that was relying on a environment variable to set the domain for Plausible.io.
The tricky thing was that I was building the container once and deploying it to multiple pods with different environment configs.

Technically docker can respect a .env file when it is run with the option --env-file like so:

docker run --rm --env-file .env -p 3000:3000 -d YOUR_CONTAINER_TAG:prod
Enter fullscreen mode Exit fullscreen mode

So here comes the issue...

But since the environment was set during build time inside the container and NextJS has automatic site optimiziation and builds pre-rendered pages for server-side render during build, the environment variables from the Docker build run were baked into the image and it did not care about the .env file for server logic.

A small bash script to the rescue

I am using Envault to manage environment configs and since the image is being build with a Jenkins pipeline, the pipeline pulls the correct .env file from Envault each time.
Inside the Dockerfile, change the vars to be this:

ARG DB_USER
ARG DD_SVC_NAME
ENV DB_USER=$DB_USER
ENV DD_SVC_NAME=$ARG DD_SVC_NAME
Enter fullscreen mode Exit fullscreen mode

This means the build command needs to contain --build-arg paramters for each variable.
To read those from the .env file via bash, we can use this:

$(for i in `cat .env`; do out+="--build-arg $i " ; done; echo $out;out="")
Enter fullscreen mode Exit fullscreen mode

The docker command looks like this:

docker build -f Dockerfile -t MYTAG:prod $(for i in `cat .env`; do out+="--build-arg $i " ; done; echo $out;out="") .
Enter fullscreen mode Exit fullscreen mode

Bonus round: makefile

Since I love Makefiles, there is a small pitfall how to include the bash loop into the command, so here is my Makefile for reference:

SHELL := /bin/bash
...
# this line will set the build args from env file
DECONARGS = $(shell echo "$$(for i in `cat .env`; do out+="--build-arg $$i " ; done; echo $$out;out="")")
GEN_ARGS = $(eval BARGS=$(DECONARGS))

.PHONY: dist-prod
dist-prod:
    @echo "Running docker build for PROD ..."
        $(GEN_ARGS)
    docker build -f Dockerfile -t $(TAG_SHA) $(BARGS) .
...
Enter fullscreen mode Exit fullscreen mode

Comments 6 total

  • Al - Naucode
    Al - NaucodeSep 15, 2022

    That was a nice read! Liked, bookmarked and followed, keep the good work!

  • nhm1990
    nhm1990Jan 25, 2023

    Thanks! But as it seems we have no other way to solve it (passing build-arg's is also recommended by docker).

    I've been looking for hours how to optimise the process of my Azure pipeline.... The Docker concept "Build the Docker image only once, push it to the registry only once, deploy it anywhere and anytime." is not working in my case....

    Greetings from Ludwigshafen! ;-)

  • Akshit
    AkshitNov 10, 2023

    I need to promote the same image from say dev environment to staging environment. Can you help me in this?
    Even if I use env defined variables from vault, vars will be environment specific and will require to re-trigger image build, right?

    Thanks

  • Lakshya Singh
    Lakshya SinghMar 6, 2024

    Thanks for this helped me solve the problem

  • Falk Köppe
    Falk KöppeJul 12, 2025

    Thank you for the script, much appreciated.

    I had an issue when the .env values had a space character, so I used a slightly different command to create the --build-arg arguments inspired by stackoverflow.com/a/22081170/392898.

    out=""; while read line; do if [ "$line" ]; then; out+="--build-arg $line "; fi; done < ".env"; echo $out;
    
    Enter fullscreen mode Exit fullscreen mode
Add comment