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 evenmerge
fromlodash
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 yournpm 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
andproduction.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 ofdevelopment.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
orstage
), you only need to create a JSON file in theenvironment
folder and add a script inpackage.json
(for example"start:stage": "NODE_ENV=stage node server"
or"test": "NODE_ENV=test mocha"
). No need to addif
statements inenvironment/index.js
.
A small downside:
- If the value of
NODE_ENV
is a string for an environment that is not expected (such asNODE_ENV=abc123
) then the app will crash becauseconfiguration.abc123
isundefined
, 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.