Next.js app bundles the env variables during build time. That's why I need to pass env variables as args and used them during the build stage. Now as part of the CD/CI pipeline I want to pass args dynamically via environment variables declared in compose.yaml. However, the env variable from compose file are not read during build time. In fact, the terminal prints the following message:
time="2024-12-12T23:35:10-05:00" level=warning msg="The "NEXT_PUBLIC_GRAPHQL_SERVER" variable is not set. Defaulting to a blank string."
Compose.yaml
services:
frontend:
build:
context: ./frontend
args:
- NEXT_PUBLIC_GRAPHQL_SERVER=${NEXT_PUBLIC_GRAPHQL_SERVER}
env_file:
- ./frontend/.env
environment:
NODE_ENV: production
NEXT_PUBLIC_GRAPHQL_SERVER: http://localhost:3000/
ports:
- 8080:8080
dockerfile:
FROM base AS builder
WORKDIR /usr/src/app
COPY --from=deps /usr/src/app/node_modules ./node_modules
COPY . .
ARG NEXT_PUBLIC_GRAPHQL_SERVER
ENV NEXT_PUBLIC_GRAPHQL_SERVER=${NEXT_PUBLIC_GRAPHQL_SERVER}
RUN npm run build
All works fine when I explicitly set the env variable in args but that's not the desired workflow.
services:
frontend:
build:
context: ./frontend
args:
- NEXT_PUBLIC_GRAPHQL_SERVER=http://localhost:3000/
You need to distinguish between the environment(s) you are preparing for the build, for the container runtime, and for compose itself.
Docker compose itself, when it is first parsing the compose.yml file does not use the env_file:
to expand any ${VAR} directives in the compose.yml - that directive is for injecting variables into containers.
As such, dockers own environment is the source of variables: A .env
file in the same folder as the compose.yml, any environment variables that are exported prior to executing docker compose are the sources for variable expansion in the compose.yml.