6

I'm developing a nodejs api in my free time, and I'm trying to implement testing now. I'm currently loading my environment variables from a .env file (loaded using dotenv), which include the DB_URI, DB_USER and DB_PASSWORD for my development mongodb database.

Now, I would like to create a separate database for testing however I don't know how would I load different variables to connect to the testing database instead of the development database. I deploy to Heroku where I have different environment variables so that's covered just fine.

I've tried to find online for some answers for best practices, but I have been unable to. I thought of creating a different .env file, however that's not recommended according to the documentation on npmjs..

Other resources recommended recommended hard coding the specific variables I needed in the package.json script. However, the script would be huge if I had to change all the variables needed to connect to a different database.

Can I get some help understanding how I should do this?

Thanks!

PS: In case it's needed, I'm using mocha and supertest for my tests.

sbolel
  • 3,486
  • 28
  • 45

2 Answers2

26

You can use the dotenv package as follows:

  1. In your .env file, add variables for each environment:

    DB_URI_DEVELOPMENT="https://someuri.com"
    DB_USER_DEVELOPMENT=someuser
    DB_PASSWORD_DEVELOPMENT=somepassword
    
    DB_URI_TEST="https://otheruri.com"
    DB_USER_TEST=otheruser
    DB_PASSWORD_TEST=otherpassword
    
  2. Start the application in development:

     NODE_ENV=development node server.js
    

    or in test:

     NODE_ENV=test node server.js
    
  3. Access the environment variables in your app:

    /**
     * This `if` block prevents loading of the .env file on Heroku by calling
     * dotenv.config() if and only if `NODE_ENV` is not equal to "production"
     *  
     * In order to set environment variables on Heroku, use "config vars":
     * @see {@link https://devcenter.heroku.com/articles/config-vars}.
     *
     * If you must use `dotenv` to load an .env file on Heroku, follow:
     * @see {@link https://stackoverflow.com/a/54884602/1526037}.
     */
    if (process.env.NODE_ENV !== 'production') {
      require('dotenv').config();
    }
    
    // Get the current environment, and convert to uppercase (e.g. "PRODUCTION").
    const env = process.env.NODE_ENV.toUpperCase();
    
    // Access the environment variables for the current environment
    // by postfixing them with the uppercase environment string.
    const {
      [`DB_URI_${env}`]: dbUri,
      [`DB_USER_${env}`]: dbUser,
      [`DB_PASSWORD_${env}`]: dbPassword,
    } = process.env;
    
    /*
     * Note, the above is the same as:
     * ---------------------------------------------------------
     * var dbUri = process.env['DB_URI_' + env];
     * var dbUser = process.env['DB_USER_' + env];
     * var dbPassword = process.env['DB_PASSWORD_' + env];
     */
    
sbolel
  • 3,486
  • 28
  • 45
  • 1
    Hi @sbolel Is this solution heroku compatible ? – Enrique Aug 03 '21 at 15:48
  • 1
    Yes it is @Enrique. For Heroku, you have two options for defining environment variables. 1) you can use `dotenv` only locally, and for production, define ["config vars"](https://devcenter.heroku.com/articles/config-vars) in the Heroku interface and access them in your app as environment variables (`process.env`), or (2) you can use `dotenv` in production as well, by following [the directions in this answer](https://stackoverflow.com/a/54884602/1526037). – sbolel Sep 17 '21 at 19:45
  • 1
    @Enrique you're welcome! hope that solves the issue. – sbolel Dec 03 '21 at 19:09
0

Personally I like having the same environment variable names for different environments, so I created a env.ts to include where I want to load my dotEnv so I can use the same environment variable names throughout my application.

import * as process from "process";
import * as dotenv from 'dotenv'
import * as path from "path";

const getDotEnvPath = (env?: string) => {
    if (env == 'TEST') {
        return '.env.test'
    }
    return '.env'
}
dotenv.config({path: path.resolve(process.cwd(), getDotEnvPath(process.env.NODE_ENV?.toUpperCase()))})

Its also good to note that by default dotEnv only sets the environment variables when they are not already set.

Maarten van Middelaar
  • 1,691
  • 10
  • 15