Node.js environment variables! The Right Way.

July 12, 2019
5 min read

Environment variables are very fundamental part of developing with Node.js or any server side language. They always contains very sensitive data and doesn't meant to be shared with outside world. You have to make sure that your server is properly configured to make use of correct variables for both development and production environments. Any mistake can lead your server to crash.

Working with environment variable in Node.js is very easy and simple. This post will walk you through the different approaches of using environment variables in Node.js.

If you want to learn about environment variables in Node.js in click here.

1. Using package.json

You are thinking how? But you can pass key=value pairs directly in the npm scripts in the package.json. This is a valid a place to put environment variable but not a secure place.

Below is an example of setting Node.js execution environment to production on the npm's start script.

NOTE: This will probably won't work with Windows OS.

{
    ...
    "scripts": {
        "start": "NODE_ENV=production node bin/www.js"
    }
    ...
}

I also use this approach when I work with debug module or setting the Node.js execution environemnt. Some points to be considered when using this approach:

  • Shouldn't not put any sensitive data in here as it is visible to everyone and you can't ignore package.json in the .gitignore.
  • Don't put more than 2 variables as it could quickly becomes a mess.
  • Separating variables for development and production environment can be very hard.

2. Different keys files

This approach is completely different from first approach and addresses some of the issue of first approach.

Instead of using package.json, we can use keys.dev.js for development and keys.prod.js for production environment. Each file stores different variables for different environment.


Make sure to ignore keys.dev.js in the .gitignore before commiting any changes.


But how we can use them?

Using them can be tricky (when i initially got frustrated), So pay attention. Both files are exported by a third file i.e keys.js which checks the Node.js execution environement i.e. NODE_ENV and exports the correct keys file.

But how can I check Node.js environment before running our code? Look at the first approch for a brief. Below is an example for this approach:

// keys.dev.js ==========
module.exports = {
    PORT: 5000,
};

// keys.prod.js ==========
module.exports = {
    PORT: process.env.PORT,
};

// keys.js ==========
const devKeys = require("keys.dev.js");
const prodKeys = require("keys.prod.js");

if (process.env.NODE_ENV === "production") {
    module.exports = prodKeys;
} else {
    module.exports = devKeys;
}

This approach addresses all the issues of the first approach.

  • Multiple variables can be easily managed.
  • Development and production both have their own keys.
  • Development keys i.e. keys.dev.js can be ignored in the .gitignore keeping secrets away from others.

But no one wants to maintain extra code/file (including me). There must be a better way to do this!

3. .env comes to the rescue

.env is a special file which is used to define environment variables in Node.js. It holds key=value pairs to define the variables.


Make sure to ignore .env in the .gitignore before commiting any changes.


But, Node.js doesn't know how to read and parse this file. How do we do that? Either you could write your own logic to read and parse the file or Use a third party module to do the heavy lifting.

One popular module is dotenv (which i use) which can guide through the basic of .env file.

~ Creating the file

First create a file with name .env in the root of the project which contains all variable which will be injected in the environment by the dotenv.

# .env ======
PORT=5000
WHO_AM_I="Who Knows"

~ Configuring the dotenv

First intall the dotenv package from the npm as a dev dependencies as we don't need this in production.

npm i -D dotenv

There are several methods to load dotenv package. But, I will show you the method that i like.

To load the dotenv package and correctly read the .env file you have to modify the scripts in the package.json. Like below

{
    ...
    "scripts": {
        "start": "node bin/www.js",
        "dev": "node -r dotenv/config bin/www.js"
        // For nodemon users ====
        // "dev": "nodemon -r dotenv/config bin/www.js"
    }
    ...
}

As you can see there are two scripts

  • start for the production
  • dev for the development which loads the dotenv module

This will make sure that we don't accidentally load the dotenv in production.

~ Run the code

Now you can run the server but typing the following command.

npm run dev

And BOOM! You can now use all the variables defined in the .env file by the following syntax.

process.env.YOUR_VARIABLE_NAME;

So What kind of magic is this? What is going on? In the dev script we are telling node to preload a module by passing -r <module_name> flag. By requiring dotenv/config which read and parse the .env and sets the variable in the environment and provide access to those variable before running our code.

Now, we have a single place to define all the environment variables.

To make life a little easier, you can make a separate file i.e keys.js which exports all those variable like so we do in the second approach. This helps us to organize all the variables we use in our code.

NOTE: If you add variables in the .env then also update your exports in keys.js file.

// keys.js ======
module.exports = {
    PORT: process.env.PORT,
    WHO_AM_I: process.env.WHO_AM_I,
};

Points to be considered

  • Always ignore your development keys in the .gitignore.
  • Don't mess with NODE_ENV variable. Values other than development or production can break your app.
  • Always restart your app after changing environment variables.