What is the best way of separating "dev" and "prod" modes in the app? What is the best way of separating "dev" and "prod" modes in the app? express express

What is the best way of separating "dev" and "prod" modes in the app?


I think you're on the right path. Abstracting away the environment-specific configuration is the way to go in my opinion.

Here are a couple of remarks to enhance your code:

  • I don't think you necessarily need dotenv or even merge from lodash to make sure that your application code runs regardless of the environment it is in.
  • The object you export from environment/index.js should have the same shape for all environments to avoid errors that occur only in one environment, which is not the case in the snippets you provided.
  • I would suggest using JSON instead of JS for your config, but that's just a preference.
  • I would advise to use as little environment variables as possible. You can simply rely on NODE_ENV (or whatever single environment variable name you want) and make sure that it is defined when you run your npm start script.

Here is the code of what I would recommend to do (where ALL_CAPS strings should be replaced by the actual values you need for your app to run in that environment):

development.json

{  "port": 8080,  "db": {    "username": "DEVELOPMENT_USERNAME",    "password": "DEVELOPMENT_PASSWORD",    "name": "DEVELOPMENT_DATABASE_NAME"  },  "newfromproduction": ""}

production.json

{  "port": 8080,  "db": {    "username": "PRODUCTION_USERNAME",    "password": "PRODUCTION_PASSWORD",    "name": "PRODUCTION_DATABASE_NAME"  },  "newfromproduction": "jkdl"}

environment/index.js

import development from './development.json';import production from './production.json';const { NODE_ENV: mode } = process.env;const configuration = {  development,  production};// using a little bit of destructuring magic but that is not necessaryexport default { ...configuration[mode], mode };

package.json

"scripts": {  "start": "NODE_ENV=production node server",  "start:dev": "NODE_ENV=development nodemon server"}

And you can keep the code in server.js the same.

A couple benefits for this approach:

  • You don't have to commit development.json and production.json in your repository, so your password is safe from developers who don't need to know what it is. If a developer needs the config file to work on the app, simply share an encrypted version of development.json with them. It's not ideal but at least your password is not stored in plaintext in GitHub.
  • If you need to add other environments (such as test or stage), you only need to create a JSON file in the environment folder and add a script in package.json (for example "start:stage": "NODE_ENV=stage node server" or "test": "NODE_ENV=test mocha"). No need to add if statements in environment/index.js.

A small downside:

  • If the value of NODE_ENV is a string for an environment that is not expected (such as NODE_ENV=abc123) then the app will crash because configuration.abc123 is undefined, but that is not necessarily a bad thing (having unexpected environments is not a good idea) and you can also ameliorate the code I provided to handle that case.