Don't be fooled by NODE_ENV
When reviewing pull requests, any use of NODE_ENV
like the snippet below is an automatic flag 🚩.
if (process.env.NODE_ENV === 'production') {
onlyCallThisInProd();
}
The question to ask is:
Is this checking for our
production application environment
(i.e. example.com) or did you really intend to check if this is theproduction
JavaScript build?
What is NODE_ENV
anyway?#
NODE_ENV
is used by many frameworks and packages like react-dom
to optimize JavaScript build output, among other things.
NODE_ENV
is expected to be development
for local development environments and production
for deployed application environments.
Application environments#
I use the term "Application Environment" or even "Deployed Application Environment" to disambiguate the term "Environment". The _ENV
in NODE_ENV
is cleary short for "Environment" but you most likely have other environments at play like local, test, staging, production, etc.
Application environments may have different domains or subdomains but they most likely all (except local) have NODE_ENV
set to production so they behave as close as possible to your live production environment (the one your real uses are accessing).
name | subdomain | NODE_ENV |
---|---|---|
local | localhost:3000 | development* |
test | test.example.com | production |
staging | staging.example.com | production |
production | example.com | production |
* While most of the time your local environment will be running with NODE_ENV=development
, it should be possible to run with NODE_ENV=production
as well. This is possible in both Next.js and Create React App by running npm run build
.
So what should we do instead?#
Back to this snippet (still flagged! 🚩), how can we improve it?
if (process.env.NODE_ENV === 'production') {
onlyCallThisInProd();
}
Option 1 (preferred ✅): Use explicit environment variables#
if (process.env.THING_ENABLED === 'true') {
onlyCallThisInProd();
}
name | subdomain | THING_ENABLED |
---|---|---|
local | localhost:3000 | false |
test | test.example.com | false |
staging | staging.example.com | false |
production | example.com | true |
I prefer this option because it provides fine-grained control of execution across environments. The one downside is that it results in more environment variables, which can be cumbersome to manage.
Option 2: Use a separate environment variable that corresponds to your application environment#
To be clear, I do not recommend this option. I am only listing it here because inevitably you will consider it to salve the pain of cumbersome environment variables.
if (process.env.APP_ENV === 'production') {
onlyCallThisInProd();
}
name | subdomain | APP_ENV |
---|---|---|
local | localhost:3000 | local |
test | test.example.com | test |
staging | staging.example.com | staging |
production | example.com | production |
⚠️ This option looks tempting but it has a few downsides
- Introducing new application environments requires code changes in areas where
APP_ENV
is evaluated. - It is difficult to target specific behavior, e.g. if you wanted to partially emulate production in your local environment by allowing
onlyCallThisInProd
to be called, you don't have the ability to enable just that. There may be undesirable consequence to settingAPP_ENV=production
locally because it controls too many things.
Thanks for reading. Find me on Twitter if you have alternative suggestions.
Looking for help with a development or design project?
Reach out to work with me or other senior-level talent.
Contact me