Multiple environment files in a Next.js app (optional + with docker)

Jumanah Al Asadi
5 min readDec 9, 2021

Building a next.js app with different environment files, docker, dotenv

The most recent official documentation from Nextjs for adding environment variables in a next.js app points to creating an .env.local file at the root of your project and defining key values in there.

One rule is that if they need to start with the word NEXT_PUBLIC_ in order to be available in the front-end / browser. For example, inside of .env.local

NEXT_PUBLIC_API=http://localhost:9000/api

Another catch is that.. well.. environment variables will only be added at build time, not run time. So they must be set and available at build time. Don’t bother setting, changing them at run time, it won’t work (unless with some hacky way I haven’t figured out yet).

And with that said, you’re done, you don’t need to install dotnet or anything like that, the nextjs app will automatically look for this file when building. Just start the app and you will see a message like, “pulled environment variables from .env.local”!

If you only wish to build with this single file, and you have only one environment or two, you’re good to go. You don’t need anything in next.config either.

The second you have many environments and you’d like to build for staging, test, development and production etc.. you are likely to need multiple environment files with different values, like: .env.prod, .env.staging ..etc. Nextjs has confusing documentation for this, and albeit it did not work for me. I had to dig around for solutions online, and I finally got one working.

So I found this workaround, and it works great! Follow these steps below to get it working. Don’t worry it’s not too difficult! Finding these steps were difficult though 🤓…

Create environment files

Let’s assume we have a three environments:

  • local
  • testing
  • prod

Let’s delete the .env.local file we had initially created, if we had one.

Then we start by creating an env folder in the root of the project. Inside this folder, create create 3 new environment files:

env /.env.local.env.prod.env.testing

Don’t forget to add these files to our .gitignore so we never push them to Github or Bitbucket..

In each file, populate your environment variables with different values.

Install packages

To complete this solution, we need to install two npm packages, npm install dotenv

and npm install env-cmd they will help us add our own environment system. You may be already familiar with dotenv as it’s quite popular for implementing environment files.

Modify Next.config.js

The next.config.js file is a file where you can add custom configuration to your nextjs app. If you don’t have this file already, please create it at the root of your project.

Add the following code inside of it.

require('dotenv').config()
const webpack = require('webpack')
module.exports = {
webpack: (config) => {
config.plugins.push(
new webpack.EnvironmentPlugin(process.env)
)
return config
}
}

We’re almost done!

Add build scripts

Now we need a way to build the app, with different environment files. Since environment variables are added at build time, we need to run the build command with a specific environment file. We can use env-cmd to do this.

Let’s modify the scripts inside package.json, and add some new build scripts.

As you can see I added three new build scripts! Using env-cmd will allow us to point to an environment file when building. So we pass it the path of the file, which is located in the env folder we just created.

"scripts": {
"dev": "env-cmd -f env/.env.local next dev",
"build-dev": "next build",
"build": "next build",
"start": "next start",
"lint": "eslint --fix --ext .js .",
"build:prod": "env-cmd -f env/.env.prod yarn build",
"build:test": "env-cmd -f env/.env.test yarn build",
"build:local": "env-cmd -f env/.env.local yarn build"

},

The default build command for a production build, is next build, and next dev for a development / hot reloading building on the fly / server.

For this reason, I also added the pointer to the local environment file for running the dev command to start the app in development mode on localhost. This means we will use the env.local file when we run the following command:

yarn dev

Now we have covered all situations.

Basic Usage

So to build and run your app in a production environment you can use:

yarn build:prod 

To build in test mode, you can use:

yarn build:test

Then to start the application you just built, you can use

yarn start

Docker usage

If you would like to build your app via docker and deploy it as a container somewhere, keep on reading..

Create a Dockerfile at the root of your project: By the way, this was stolen from https://nextjs.org/docs/deployment#docker-imagehttps://nextjs.org/docs/deployment#docker-image and modified slightly.

# Install dependencies only when needed
FROM node:16.8.0-alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
# Open issue https://github.com/facebook/create-react-app/issues/11565
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json ./
RUN yarn install --frozen-lockfile
# Rebuild the source code only when needed
FROM node:16.8.0-alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
ARG BUILDCOMMAND=build:local-kb
RUN yarn $BUILDCOMMAND && yarn install --production --ignore-scripts --prefer-offline
# Production image, copy all the files and run next
FROM node:16.8.0-alpine AS runner
WORKDIR /app
ENV NODE_ENV productionRUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# You only need to copy next.config.js if you are NOT using the default configuration
# COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
USER nextjsEXPOSE 3000# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry.
# ENV NEXT_TELEMETRY_DISABLED 1
CMD ["yarn", "start"]

Normally you can just build a docker file without anything else. But I have modified this docker file to accept an arg, to make it customizable, so we can run the different build commands we just created in package.json.

So to build an image from this docker file, you can pass an argument which will tell the docker file what kind of environment you want to build for.

To build a specific environment pass the build-arg BUILDCOMMAND. There is also a default value present in the docker file if you don’t pass this. This arg was named by myself, feel free to change its name!

We can pass either: build:local, build:prod, build:test, the ones we defined in our package.json scripts. If you added more, go for it!

Example:

docker build -t next-app --build-arg BUILDCOMMAND=build:prod --no-cache .

Then we can run our docker image as a container

docker run -p 3000:3000 next-app

That’s it! Thanks for reading ^_^

--

--

Jumanah Al Asadi

I am just a web developer who loves writing, teaching and music :) My teaching style is playful and fun. At least I hope, lol :p