113

I want to use separate .env files for each mode (development, production, etc...). When working on my vue.js projects, I can use files like .env.development or .env.production to get different values for the same env key. (example: in .env.development: FOO=BAR and in .env.production: FOO=BAZ, in development mode process.env.FOO would be BAR, in production i'd be BAZ).

I'm working on an Express server and want to use these same kinds of .env files to store the port, db uri, user, pwd...

I know I can edit the scripts in package.json like this:

"scripts": {
    "start": "NODE_ENV=development PORT=80 node ./bin/www",
    "start-prod": "NODE_ENV=production PORT=81 node ./bin/www"
}

but this gets messy when using multiple variables.

I've tried using dotenv but it seems like you can only use the .env file. Not .env.development and .env.production.

Can I use the dotenv package or do I need another one? Or could I do this without any package at all?

KyleMit
  • 30,350
  • 66
  • 462
  • 664
Jonas
  • 1,153
  • 2
  • 7
  • 7
  • 3
    Welcome to Stack Overflow. Why would you need multiple environment files on one host? Normally your development and production environments are on different hosts. (dev on your computer and production in the cloud for example). – Trevor V Mar 28 '19 at 20:18
  • https://www.npmjs.com/package/dotenv#should-i-have-multiple-env-files – lifeisfoo Mar 28 '19 at 20:24
  • For reference, here is how Vue CLI lets you use multiple .env files. I think that's what Jonas refers to in the question. I find this way for working with env files very useful. https://cli.vuejs.org/guide/mode-and-env.html#environment-variables – Martin Omander Dec 18 '20 at 03:55

8 Answers8

190

You can specify which .env file path to use via the path option with something like this:

require('dotenv').config({ path: `.env.${process.env.NODE_ENV}` })
john-goldsmith
  • 2,969
  • 1
  • 19
  • 18
  • 29
    For anyone else: i finally went with this: `const path = require('path'); require('dotenv').config({ path: path.join(__dirname, `../.env.${process.env.NODE_ENV}`)}); ` – Jonas Mar 30 '19 at 09:41
  • 1
    If I use this solution I seem to need to place this line of code in every javascript file that I want to use the env values... Is there no global way so I can just have one line and all files access the values? – goldenmaza Dec 19 '20 at 19:30
  • 8
    @goldenmaza You can preload them when running your node service in terminal like this. `node -r dotenv/config app.js dotenv_config_path=/custom/path/to/your/env/vars`. See also here https://www.npmjs.com/package/dotenv – Zwe Dec 28 '20 at 23:45
  • 7
    `NODE_ENV` should not be used to set the application environment. A separate environment variable like `APP_ENV` may be used for this. You may want `NODE_ENV` to be `production` in your non production environments as well. https://nodejs.dev/learn/nodejs-the-difference-between-development-and-production – Pranaya Tomar Aug 30 '21 at 08:16
  • 1
    @goldenmaza You shouldn't need to place this in every JS file. You'll want to add this as early as possible to your application bootstrap/entry point . Once it's added, you can access environment variables via `process.env`. – john-goldsmith Dec 03 '21 at 18:39
  • @john-goldsmith Can you elaborate more on this how do we 'bootstrap/entry point' in node.js application? – User7723337 Mar 03 '23 at 09:05
  • @User7723337 I just mean the "root" of your application or script (typically `index.js`). If `index.js` calls `require('dotenv')`, then any other module that is required from that point onward will have the same environment values. – john-goldsmith May 04 '23 at 18:00
  • @PranayaTomar Why it is not recommended? It is commonly used elsewhere... also the link is broken. – Arst Jun 25 '23 at 05:29
  • 1
    @Arst NODE_ENV and APP_ENV handle separate concerns. NODE_ENV is intended to be understood by Node (and not your application logic) and has only 2 possible values - 'development' and 'production' which Node uses internally to control logging, caching etc. APP_ENV (or any other name) is defined by the application (and so can have any value) and used for application config Eg. connect to 'staging' DB. So you may even want to mix different NODE_ENV and APP_ENV values as per your needs. https://nodejs.dev/en/learn/nodejs-the-difference-between-development-and-production/ – Pranaya Tomar Jun 27 '23 at 08:06
13

The above two answers are both slightly off. let me explain. Answer from KyleMit below is missing ./ to indicate current directory.

  • the ./ indicates current directory in Node.js. The Second . prior to env indicates a hidden/private file. Thats why in KyleMits answer if the env file was not in the root of the PC it would never find it. The simplest way to do it in my opinion is to add a ./ this says "hey computer look in my current directory for this file".
//look in my current directory for this  hidden file. 
// List hidden files in dir: ls -a
 
require('dotenv').config({ path: `./.env.${process.env.NODE_ENV}` })


//I reccomend doing a console.log as well to make sure the names match*
console.log(`./.env.${process.env.NODE_ENV}`)
Josh
  • 1,059
  • 10
  • 17
7

I'm using the custom-env npm package to handle multiple .env files. Just put this at the top of your code:

require('custom-env').env();

and it will load environment variables from the file .env.X, where X is the value of you NODE_ENV environment variable. For example: .env.test or .env.production.

Here is a nice tutorial on how to use the package.

Martin Omander
  • 3,223
  • 28
  • 23
6

For TypeScript:

import dotenv from 'dotenv'
dotenv.config({ path: `.env.${process.env.NODE_ENV}` })
Roman Scher
  • 1,162
  • 2
  • 14
  • 18
4

From answers from above: This is the final result that worked for me.

.env.dev file in src dir.

import path from 'path';

dotenv.config({ path: path.join(__dirname, `./.env.${process.env.NODE_ENV}`)});
Moshe Yamini
  • 608
  • 9
  • 13
1

This work for me:

File .env

NODE_ENV=dev
DB_HOST=localhost

File .env.dev

DB_HOST=dev-host
DEV_VAR=new-variable

Code

require("dotenv").config();

if (process.env.NODE_ENV === "dev") {
  const result = require("dotenv").config({ path: ".env.dev" });

  process.env = {
    ...process.env,
    ...result.parsed,
  };
}

const dbConfig = {
  host: process.env.DB_HOST,
};

console.log(dbConfig.host);
console.log(process.env.DEV_VAR);
0

Install the dotenv package:

npm install dotenv

We need to get the .env file name based on NODE_ENV, it might be undefined, set default to development:

const envFileName = `.env.${process.env.NODE_ENV || "development"}`

Import the dotenv package and use it:

dotenv.config({ path: envFileName });
Amir2mi
  • 896
  • 9
  • 13
-5

The official doc of dotenv does not recommend having multiple .env files.

"Should I have multiple .env files? No. We strongly recommend against having a "main" .env file and an "environment" .env file like .env.test. Your config should vary between deploys, and you should not be sharing values between environments."

romerompb
  • 860
  • 11
  • 15
  • 9
    DV bc This misinterprets either OP question or the doc: the doc advice is against using multiple .env files in the same environment (eg, loading `main.env` and `test.env` in the same process), not blanket advice against having multiple files. – FrozenKiwi Mar 18 '21 at 11:04
  • 2
    Apologies for DV @rom5jp (I would remove it if I could). I re-read the docs, and it does sound like it doesn't recommend multiple files. However, I suspect this advice was not intended for this context, as it basically negates most of the utility of .env file in the first place (unless you never run multiple environments on your local machine). – FrozenKiwi Mar 19 '21 at 15:19
  • That statement in the docs is for liability purposes. If you are using dotenv for a production NodeJS server with a large team that has different roles/responsibilities, and store secrets/creds in the .env file - then yes, Dev should never have access to Prod vars (especially sensitive vars). However, you can also use this package to store non-sensitive vars that will change across envs (such as remote urls) on client-side applications (such as [this](https://create-react-app.dev/docs/adding-custom-environment-variables/)). The context defines how the package should be used. – LukeT Mar 19 '21 at 16:52
  • 5
    In my opinion, the quoted recommendation against multiple .env files is poorly written and it's not clear what they mean. I agree that your config should vary between environments. But that means you will need one env file per environment. I think @FrozenKiwi is right: the recommendation is probably against multiple env files for one particular environment. – Martin Omander Jun 04 '21 at 21:14
  • I too was confused by dotenv's official statement. But what FrozenKiwi writes makes sense to me. They oppose the idea of multiple .env on a single environment. Not that we shouldn't have multiple .env to track each environments. – Miquel Canal Dec 21 '21 at 12:50
  • I will even add and say - testing will always require the same configuration across different environments (local/ci etc.). To guarantee consistent configuration for testing, you should commit that file as part of the code. If the configuration includes secrets, encrypt it and only pass the decrypt key around. – guy mograbi Jan 26 '22 at 18:31
  • @guymograbi I'm not sure if I understand your comment fully, but that may not be true if your _test_ is writing to a database, or if you want to turn off logging (via environment variable). The test should require its own configuration and that test configuration may look different on your local machine vs the remote machine; and may be different from the local development environment and remote deployment environment. – Mike Apr 23 '22 at 18:40
  • 1
    I think we've all been confused by the dotenv's wording. They say _`We strongly recommend against having a "main" .env file and an "environment" .env file like .env.test. Your config should vary between deploys, and you should not be sharing values between environments.`_, which seems like it discourages overrides/combinations -- the "AND" is the operative word. I think he majority of us are more curious about different local environments (e.g., `.env.development`, `.env.production`, etc) to test code locally w/ different resources. – Mike Apr 23 '22 at 18:43
  • 1
    I also want to highlight their expectations/advice in how the .env is intended to be used. They say _`It should only include environment-specific values such as database passwords or API keys`_, which might explain why they don't expect to use a combination of environment files. Per: https://github.com/motdotla/dotenv#should-i-commit-my-env-file – Mike Apr 23 '22 at 18:48
  • Really use case specific. – Jesse de gans Apr 27 '22 at 15:55