63
Manage NEXT_PUBLIC Environment Variables at Runtime with Docker
Next.js is definitely a very good solution for making modern web applications, it's fast, simple, and reliable. It works very well also with Docker, you can build a production image with a few lines of Dockerfile, and deploy your app to the world.
However, there is a problem: when you build your docker image, and your app requires some client-side environment variables, (the famous NEXT_PUBLIC_) env vars, these variables will be set during build time, and you will no longer have a way to change them.
Well, a quite tricky solution is to do the variable replace directly on runtime as docker image entrypoint! Let's see an example:
Suppose you have to set up an API_URL endpoint for your client, obviously, you will set up something like that:
NEXT_PUBLIC_API_URL=
What we can do on the Dockerfile, is something like that:
# Install dependencies only when needed
FROM node:14-alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# Rebuild the source code only when needed
FROM node:14-alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN NEXT_PUBLIC_API_URL=APP_NEXT_PUBLIC_API_URL npm run build
# Production image, copy all the files and run next
FROM node:14-alpine AS runner
WORKDIR /app
ENV NODE_ENV production
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/entrypoint.sh ./entrypoint.sh
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
RUN chown -R nextjs:nodejs /app/.next
USER nextjs
EXPOSE 3000
RUN npx next telemetry disable
ENTRYPOINT ["/app/entrypoint.sh"]
CMD npm run start
This is a common Next.js dockerfile, but attention must be payed to this row:
RUN NEXT_PUBLIC_API_URL=APP_NEXT_PUBLIC_API_URL npm run build
The build will be launched with an environment placeholder in this row, so your API_URL will be temporarily set to a string with value: APP_NEXT_PUBLIC_API_URL.
After the image build, we set a custom entrypoint called entrypoint.sh
ENTRYPOINT ["/app/entrypoint.sh"]
This file contains a set of specific instructions:
#!/bin/sh
echo "Check that we have NEXT_PUBLIC_API_URL vars"
test -n "$NEXT_PUBLIC_API_URL"
find /app/.next \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i "s#APP_NEXT_PUBLIC_API_URL#$NEXT_PUBLIC_API_URL#g"
echo "Starting Nextjs"
exec "$@"
When the docker image starts, the entrypoint will replace all the previously set environment placeholders, with the real values, passed by the NEXT_PUBLIC_API_URL environment variable!
So you can pass your value directly for example in your
docker-compose.yml
:version: "3.7"
services:
ui:
image: ghcr.io/useaurora/aurora/aurora
ports:
- "3000:3000"
environment:
NEXT_PUBLIC_API_URL: http://localhost:5000
Or also in your command line interface:
docker run -e NEXT_PUBLIC_API_URL="http://localhost:5000" ghcr.io/useaurora/aurora/aurora
This is all you need to do to accomplish this solution!
A couple of things to remember:
Thank you for reading this article, I really appreciate it. Please leave a reaction if the article helped you.
If you want you can follow me on Twitter
Seeya!
63