Managing secrets and environmental variables in Node Js

Every code project requires to maintain secrets, configurations, and environment-specific variables.

The most common secrets are,

  • Database connecting strings and passwords
  • Email service account and passwords
  • Third-party services API keys

Common environmental variables are,

  • Port number
  • Application environment (eg., NODE_ENV - test, development, production)

Other application-specific configurations like,

  • Default email address
  • Feature toggle variables

The first option is to manage it inside your code. But this won't work well if you keep your code in the remote repository (e.g, Github, GitLab, etc).

Also, this won't work if you are in a multi-developer environment. Every developer uses a different config that can't be hard-coded in the code.

This problem can be fixed in production by setting system environment variables. This variable can be accessed through process.env in your application.

But in development, you will have many applications on your computer. Most variables are the same for different applications. So you need to find a way to use this variable application-specific.

There is an awesome package to solve this issue in development. It is called as dotenv

dotenv helps to manage your environmental variables and configuration inside your application code.

Let's install dotenv,

npm install dotenv

Create a .env file in the root of the project.

  file: .env


Let's create a simple node Js application and use dotenv in server.js file,

  file: server.js

const http = require('http');
const express = require('express');
// import dotenv package
const dotenv = require('dotenv');

// Use `.env` config when the NODE_ENV is other than production
if (process.env.NODE_ENV !== 'production') {

const app = express();

// Root URL will serve all the process env values from the .env file
app.get('/', (req, res) => {
    node_env: process.env.NODE_ENV,
    port: process.env.PORT,
    api_root_url: process.env.API_BASE_URL,
    client_secret: process.env.CLIENT_SECRET,
    port_lowercase: process.env.port || null // Will be null, since env variables are case sensitive

// Read port from PORT env variable or use 8080
const port = process.env.PORT || 8080;
const server = http.Server(app);

server.listen(port, () => {
  console.log(`Server listening on port: ${port}\n`);

Our code use dotenv for the environment other than production. It reads the port value and NODE_ENV from the .env file.

Start the server and check the root URL, http://localhost:8080

This will be the result,

  "node_env": "development",
  "port": "8080",
  "api_root_url": "http://localhost",
  "client_secret": "xydwy10290askajs",
  "port_lowercase": null

As you see, these env keys are case sensitive.