I write software locally, push it to remote Git server, where if the tests pass it gets deployed to staging environment. If the staging environment works correctly, then I will deploy the software to production. I often use
NODE_ENV environment variable to flag these three environments. By default, the environment variable is unset and defaults to
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
Depending on the
NODE_ENV my program could load different settings: urls, logging parameters, server routes. Often, it is a YAML or a JSON file with environment names as keys
When running on staging or production, I set
NODE_ENV variable on the server to
production. This value then lets my code load right config for the environment. If
npm install and
npm ci install production NPM dependencies. So there is a catch:
- On staging with
npm ciwill install production AND dev dependencies
- Thus staging will NOT be exactly like production.
Staging would run just fine if one of the dependencies was saved as dev dependency by mistake, but the same application would crash in production because that dependencies would not be present.
npm install call with conditional to add
--production flag when running on staging and production would create a nasty shell command. Luckily NPM thought about this. There is an additional environment variable we can set to install only the production dependencies on staging - it is
NPM_CONFIG_PRODUCTION which acts just like
--production during install step.
But watch out! Setting
NPM_CONFIG_PRODUCTION=true during install overrides
NODE_ENV for all npm scripts, which is what NPM intended. So the server will behave differently if you call
node ./start.js or
Server starts with
process.env.NODE_ENV=staging value. But if you have NPM script
start that does the same in
package.json the result will be different.
Server starts with
We got burnt by this once - good thing we have noticed error reports from
staging being written to the production dashboard, and figured why the staging server was running against production before any production data was corrupted.
There are two solutions.
process.env.NODE_ENV in every entry point with a different variable like
You have to be 100% sure that every script -
db/migrations.js goes through the same override first. Otherwise some script might still be executed against production, which is ... less than ideal.
2. Use another variable to pick the environment settings, and leave
NODE_ENV alone. For example, the variable
SETTINGS could be
NODE_ENV will be always be undefined or
process.env.SETTINGS = process.env.SETTINGS || 'development'
The second method is my preferred one - but it might not be supported by every config-loading library. So find a config library that does allow you to specify a different variable from
NODE_ENV. For example config allows using NODE_CONFIG_ENV to specify environment to load.