62

I would like to have different configuration files for the environment variables and be able to use them in my next project. I saw the example with dotenv.

But I don't like to define the variables in the .env file and also define them in the config.next.js file. if for some reason I put the variables in the .env file but forget to put them in the config.next.js file the code starts having problems. Theres is a way to do it more eficiently?

My scripts in package.json:

"scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start",
    "lint": "eslint pages --ext .ts,.tsx,.js",
    "test": "jest",
    "commit": "git-cz",
    "dev:production": "dotenv next"
},

My .env vars

TITULO=react, typescript, material ui App

Component

import { NextPage }          from 'next';
import { FunctionComponent } from 'react';

interface HelloWorldProps {
  nombre: string,
  saludo?: string
}


const HelloWorld: FunctionComponent<HelloWorldProps> = ({ nombre, saludo = 'noches' }: HelloWorldProps) => (
  <>
    <h1>Hola {nombre} buenas {saludo}</h1>
    {/* eslint-disable-next-line multiline-ternary */}
    <h2>{process.env.TITULO ? 'hola' : 'adios'}</h2>
  </>
);

const Home: NextPage = () => <HelloWorld nombre="cristian" />;

export default Home;

Saurish Kar
  • 576
  • 7
  • 13
Cristian Flórez
  • 2,277
  • 5
  • 29
  • 51

11 Answers11

80

Next 9.4 has built-in support for .env files: https://nextjs.org/docs/basic-features/environment-variables

But, in case you want to have multiple .env files, like:

  • .env.development
  • .env.staging
  • .env.prestaging
  • .env.production

It would be impossible to do with a built-in env variables support. There's only 3 environments that officially supported for now, it's: "development", "test", "production". With next dev you use "development", next build && next start uses "production" environment.

If you need to build for production environment, but using ".env.staging" for example, then you need to add env-cmd package, and add this line to your package.json:

"build:staging": "env-cmd -f .env.staging yarn build && yarn start"

Next would make a production build with ".env.staging" variables.

Alexander Kim
  • 17,304
  • 23
  • 100
  • 157
  • 5
    With next dev you use "development", next build && next start uses "production" environment and how to run in "test" environment then? – bugwheels94 Dec 22 '20 at 01:46
  • 1
    This works good to start the application locally. But then when you deploy in my case it it doesn't load environment variables. I have one default .env and on build I add .env.staging for example. On deployed version only variables from .env are showing? Can you help me with that? – ROKIKOKI Jan 25 '21 at 15:29
  • 3
    This is ok, but it wont work with the Docker build once run anywhere as you would need to build with different commands. This is the solution: https://github.com/andrewmclagan/react-env – AndrewMcLagan Mar 04 '21 at 01:45
  • 3
    Great tip about `cmd-env`. Btw, looks like it should be an option on nextJs =) – Wendell Pereira Jul 09 '21 at 15:55
  • 10
    @WendellPereira It definitely does, it is ridiculous we need to install external libraries for handling environments --' – Matheus Ribeiro Jul 28 '21 at 12:44
  • 3
    This does not work with `next: 9.5.3` and `env-cmd: ^10.1.0`. It keeps load the production env no matter what env supplied to `env-cmd`: `$ env-cmd -f .env.development next start info - Loaded env from /Users/username/projects/ex/.env.production` – Phạm Tuấn Anh Oct 24 '22 at 03:53
  • @PhạmTuấnAnh I am facing exactly the same issues, did you found out any other solution that worked ? – zsubzwary Nov 16 '22 at 06:58
  • @zsubzwary unfortunately no. I end up just place all env variables in the .env.production file then comment/uncomment them accordingly – Phạm Tuấn Anh Nov 17 '22 at 07:02
  • Try this answer I wrote. It works with Next 13 and doesn't have any dependency. https://stackoverflow.com/a/76724510/3556531 – KeshavDulal Jul 19 '23 at 19:21
30

The issue with most of these answers is they go against the principal of "build once run everywhere", in reality most of us are using this technique build and run with Docker containers. It's not possible to have multiple build commands like this, and it would be bad practice.

Better have your environment available at runtime. We created a package that allows next static optimisation and still have runtime env vars via window.__ENV

https://github.com/andrewmclagan/react-env

This works by generating an environment config object at runtime from whitelisted env vars:

{
  ...
  "scripts": {
    "dev": "react-env -- next dev", // where .env.${APP_ENV}
    "start": "react-env --env APP_ENV -- next start" // where .env.${APP_ENV}
  }
  ...
}
AndrewMcLagan
  • 13,459
  • 23
  • 91
  • 158
  • 13
    Coming from other environments and being absolutely dumbfounded that NextJS does it this way, thank you for being a voice of reason. – kevlarr Jul 27 '21 at 20:12
  • Also been googling around for a while, just confused at the "default" way env is handled in next - thank you – Phantomwhale Aug 11 '21 at 04:28
  • How to pick an API base URL from the process environment after the build? If the actual URL is unknown during the build and will be passed to the Docker container on startup? – Alexander Pravdin Aug 12 '21 at 11:18
  • see the documentation for this package. You can do that. – AndrewMcLagan Aug 18 '21 at 03:20
  • I was supremely frustrated to find that NextJS expected me to build seperate bundles for staging and production environments, this package is a great approach to solving a common problem and should be part of the core framework – linked May 30 '22 at 19:22
20

You can have different .env files in nextjs with following two ways:

1. Using env-cmd package

Provide the path to your environment file in the scripts like:

"scripts": {
    "start": "env-cmd path/to/prod/env/file next start",
    "start:dev": "env-cmd path/to/prod/env/file next dev",   
    "build:dev": "env-cmd path/to/dev/env/file next build",
    "build:test": "env-cmd path/to/test/env/file next build",
    "build:stage": "env-cmd path/to/stage/env/file next build",
    "build": "env-cmd path/to/stage/prod/file next build",        
},

2. Using dotenv package

In your next.config.js file add following:

require("dotenv").config({ path: `${process.env.ENVIRONMENT}` });

module.exports = {
      // your configs
}

and in your scripts, provide that ENVIRONMENT variable like:

"scripts": {
    "start": "ENVIRONMENT=path/to/prod/env/file next start",
    "start:dev": "ENVIRONMENT=path/to/dev/env/file next dev",
    "build:dev": "ENVIRONMENT=path/to/dev/env/file next build",
    "build:test": "ENVIRONMENT=path/to/test/env/file next build",
    "build:stage": "ENVIRONMENT=path/to/stage/env/file next build",
    "build": "ENVIRONMENT=path/to/stage/prod/file next build",        
},

NOTE: The thing is do not to put your .env* files in the root folder, otherwise NEXT will auto-pick from your .evn* files and it only supports production and development stages. So it'll ignore other .env.my-stage files.

Vrajpal Jhala
  • 231
  • 3
  • 8
  • hi. is the `env-cmd` needed for the `next start` command? I think the variables are inlined during the build and `next start` just runs that build, am I right? – Richard Trembecký Oct 05 '21 at 20:06
  • 1
    @RichardTrembecký, yes that's correct. Without production build, `next start` won't work and `env-cmd` injects variables during build. – Vrajpal Jhala Oct 07 '21 at 14:39
  • Module not found: Error: Can't resolve 'fs' in 'C:\admin\node_modules\dotenv\lib' – Sunil Garg Oct 20 '21 at 07:35
  • for env-cmd, you can use -f to force using a specific env file if your envs are on root folder: "env-cmd -f .env.dev next build" – Alon Laniado Jan 05 '23 at 08:13
5

This day and age you shouldn't need to install anything extra to implement multiple environment configuration! See GitHub repo NextJS template with config management

Next.js v9.4 and up has a more intuitive and ergonomic way for adding environment variables:

{
  "name": "package.json",
  "scripts": {
    "dev": "next dev",
    "build": "next build && next export",
    "build-dev": "TARGET_ENV=development next build && next export",
    "build-staging": "TARGET_ENV=staging next build && next export",
    "test": "jest --watch"
  }
}
{
  "name": "env.json",
  "development": {
    "APP_ENV": "development"
  },
  "production": {
    "APP_ENV": "production"
  },
  "staging": {
    "APP_ENV": "staging"
  },
  "test": {
    "APP_ENV": "test"
  }
}
// next.config.js v9.4+
const envConfig = require('./env.json')
const environment = process.env.TARGET_ENV || process.env.NODE_ENV

const nextConfig = {
  env: envConfig[environment], // getEnvConfig()
}
module.exports = nextConfig

function getEnvConfig() { // for multi-file config
  try {
    return require(`./env-${environment}.json`)
  } catch (err) {
    return require('./env.json')
  }
}
npm run dev # process.env.APP_ENV=development
npm run build # process.env.APP_ENV=production
npm run build-dev # process.env.APP_ENV=development
npm run build-staging # process.env.APP_ENV=staging
npm run test # process.env.APP_ENV=test
piouson
  • 3,328
  • 3
  • 29
  • 29
  • 1
    that doesn't make much sense to me in a container world. We shouldn't be building per-environment. The build should be only one and use ENV variables at run time, which is what ENV VARS are for, right? – JorgeeFG Jan 26 '23 at 13:19
  • hate it or leave it, today many organisations still using static site exports dumped in wherever random cloud bucket in production.. – piouson Feb 03 '23 at 00:19
4

npm i dotenv

Then add below code to next.config.js, restart the application and you are good to go!

// next.config.js

require('dotenv').config()
const webpack = require('webpack')

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

If your .env file is not located in same folder as next.config.js add path to your config like below,

require('dotenv').config({ path: 'path/to/.env' })
Hasan Sefa Ozalp
  • 6,353
  • 5
  • 34
  • 45
4

For anyone interested to use .yml file for easy management of environment variables, here's how I did it.

Install a plugin yenv in devDependencies.

Add the below config in next.config.js :

const path = require("path");
const yenv = require("yenv");
const { PHASE_DEVELOPMENT_SERVER } = require("next/constants");

module.exports = (phase) => {
  const isDev = phase === PHASE_DEVELOPMENT_SERVER;
  const NEXT_ENV = isDev ? "development" : process.env.APP_ENV;
  const rawEnv = yenv(path.resolve(".env.yml"), { raw: true, env: NEXT_ENV });
  
  return {
    ...some other config,
    env: getEnvVars(rawEnv, isDev).raw,
    compress: true,
  };
};

function getEnvVars(rawEnv, dev) {
  const NEXT_PUBLIC = /^NEXT_PUBLIC_/i;
  const raw = Object.keys(rawEnv)
    .filter((key) => NEXT_PUBLIC.test(key))
    .reduce((env, key) => {
      env[key] = rawEnv[key];
      return env;
    }, {});
  // Stringify all values so we can feed into Webpack DefinePlugin
  const stringified = {
    "process.env": Object.keys(raw).reduce((env, key) => {
      env[key] = JSON.stringify(raw[key]);
      return env;
    }, {}),
  };
  return { raw, stringified };
}

Now just add different build commands based on environment in package.json scripts.

"scripts": {
    "dev": "node server.js",
    "build:production": "APP_ENV=production next build",
    "build:staging": "APP_ENV=staging next build",
    "start": "NODE_ENV=production node server.js"
  },

Now you can use your environment variables via a single file .env.yml like this :

base:
  NEXT_PUBLIC_SECRET_KEY : ""
  NEXT_PUBLIC_ANOTHER_SECRET: ""

development:
  ~compose: base
  NEXT_PUBLIC_SECRET_KEY: "bnbnfjf"

staging:
  ~compose: base
  NEXT_PUBLIC_SECRET_KEY: "absadsad"

production:
  ~compose: base
  NEXT_PUBLIC_SECRET_KEY: "lasjdasodsdsad"

Now you can call npm run build:production to load production env vars and npm run build:staging for staging env vars.

This provides the benefit of having any number of envs for your use case. You will just have to add a build command, and update env vars in .env.yml and you are good to go.

Saurish Kar
  • 576
  • 7
  • 13
1

If you would like to use it without any 3rd party library you can expose it from the script directly with NEXT_PUBLIC_ at the start of the script, for example:

"scripts": {
  "start": "NEXT_PUBLIC_APP_ENV=development next dev"
}

than use it with

console.log(process.env.NEXT_PUBLIC_APP_ENV); // >>> development
r3dm4n
  • 1,175
  • 2
  • 18
  • 33
x-magix
  • 2,623
  • 15
  • 19
  • I guess someone did not got it correct, or maybe version problems, but I am using it for many projects – x-magix Dec 27 '21 at 12:30
0

You can use dotenv-cli and then set up different .env files for different environments in your package.json. Something like:

{
  ...
  "scripts": {
    "dev:production": "dotenv next", // Uses .env file
    "dev:staging": "dotenv -e .env.staging next" // Uses .env.staging file
  }
  ...
}
I'm Joe Too
  • 5,468
  • 1
  • 17
  • 29
  • 1
    It's giving me an error of `dotenv` not found. Although I have installed it and working properly with local file – Rehan Sattar Mar 13 '20 at 13:15
  • 1
    `dotenv -e .env.development next build` still loads production config – Dariusz Bacinski Dec 10 '21 at 10:44
  • it still load the production env. I end up with just comment / uncomment variables inside the production env file. so ridiculous!!! – Phạm Tuấn Anh Oct 24 '22 at 04:15
  • `NODE_ENV` determines if `.env.development` or `.env.production` file is loaded. You should use different env file names for your "application environment" by using `.env.app.development` and `.env.app.production` for example. – Metu Aug 23 '23 at 14:52
0

For those who still seek a solution for their faulty project, in my case my npm run dev script was "next dev src/" Getting rid of that immediately started loading .env files for me. Maybe give it a try.

A screenshot of my lovely fix

Burak Eker
  • 1
  • 1
  • 2
0

Short Answer

  1. Put your dev-env secrets in .env.dev
  2. Put your prod-env secrets in .env.prod
  3. Don't save secrets in .env.local. They will be brought there next.
  4. Add following to your package.json script.
"build-dev": "cp .env.dev .env.local && yarn build",
"build-prod": "cp .env.prod .env.local && yarn build"
  1. Upvote & Enjoy if it worked.

Additionally,

  1. You may want to add a variable APP_ENV.
  2. Set it to development and production based on file.
  3. Access process.env.APP_ENV based on your script invocation.

Long Answer

Well this is Mid-2023 and I wish there was a straightforward solution. Here's what works for me coming from React/vite to Nextjs with 2 different environments file.


Using Rodrigo's answer I first renamed

  • .env.development to .env.dev
  • .env.production to .env.prod

so that next.js doesn't pick them automatically during builds but they stay on local system.

If I don't do that then precedence kicks in and picks .env.production during deployment to my dev environment which I don't want.

Next I modified my scripts in package.json as

"build":"yarn build"

"predeploy": "cp .env.dev .env.local",
"deploy": "firebase use development && firebase hosting:channel:deploy dev",

"predeployprod": "cp .env.prod .env.local",
"deployprod": "firebase use production && firebase deploy -P production"

Read about Next JS Precedence Order briefly.

What this does is based on my "invocation" whether I want to deploy to dev/prod env it supplies the right secrets to the .env.local file.

For example, Say I want to deploy to dev. I run yarn deploy -> automatically runs yarn predeploy first setting my dev-secrets to .env.local. Secondly it runs the build.

You might wonder where's nextjs's build command? firebase deploy takes care of that and runs it behind the scene.

If you aren't using firebase following could suffice.

"build-dev": "cp .env.dev .env.local && yarn build",
"build-prod": "cp .env.prod .env.local && yarn build"

Originally answered here.

KeshavDulal
  • 3,060
  • 29
  • 30
-1

Next 9.4 support out of the box environment variables and included support for multiple environments.

New Environment Variables Support

  • Environment variables are only available in the Node.js environment by default
  • Environment variables prefixed with NEXT_PUBLIC_ are exposed to the browser

Exposing Environment Variables

Next.js allows you to expose variables using an environment variables file (.env), with included support for multiple environments. It works like this:

  • .env - Contains environment variables for all environments
  • .env.local - Local variable overrides for all environments
  • .env.[environment] - Environment variables for one environment. For example: .env.development
  • .env.[environment].local - Local variable overrides for one environment. For example: .env.development.local
Cristian Flórez
  • 2,277
  • 5
  • 29
  • 51
  • 7
    but how can I start app that would use `.env.staging`? – Dariusz Bacinski Dec 10 '21 at 10:39
  • 3
    Reason for downvote: This thread is concerned with being able to setup NextJS to run against multiple environments like : dev, qat, uat, staging, production - the out of the box environment variables do not support this - so copy/pasting this feature from the NextJS site doesn't really answer the quesiton – JTech Oct 04 '22 at 05:15