by-node-env
Run package.json scripts by NODE_ENV
.
Installation
Install with npm:
npm install by-node-env
Install with pnpm:
pnpm install by-node-env
Install with Yarn:
yarn add by-node-env
Features
Problem
When developing a Node.js application in development
mode, we often start our application with one of these different commands: npm start
, npm run dev
, npm run serve
, etc. In addition, we also explicitly set NODE_ENV=development
as an environment variable for our application to work as expected.
When deploying to production
, we often use one of these different commands: npm start
, npm run prod
, npm run serve
, etc. NODE_ENV=production
is a must-have environment variable in this situation.
The package.json might look like this for the situations mentioned above:
{
"scripts": {
// Different scripts for each NODE_ENV.
"dev": "NODE_ENV=development node src",
"prod": "NODE_ENV=production node build",
"serve": "npm run dev",
"start": "npm run prod",
"test": "jest"
}
}
When simultaneously working on multiple projects each with a different startup command, it could be very troubling and forgetting, especially under heavy cognitive load. As a result, we often waste our precious time consulting the README or the scripts section in package.json.
Solution
package.json
{
"scripts": {
"start": "by-node-env",
// Listing all start scripts by NODE_ENV like this is way more concise and explicit.
"start:development": "node src",
"start:test": "npm test",
"start:production": "node build",
"test": "jest"
}
}
npm start
has been the de facto way of starting a Node.js application for a very long time.
Besides that, to ensure that our application runs in the mode we desired, NODE_ENV
is often set as an environment variable. A lot of popular frameworks expect NODE_ENV
to be set as well.
Why not combine both, so that when we execute npm start
when NODE_ENV=production
, npm run start:production
will be spawned.
Similarly, executing npm start
when NODE_ENV=development
will spawn npm run start:development
.
Even when NODE_ENV=test
, npm start
can set to spawn npm run start:test
too. Some might disagree with this and would instead do npm test
. However, you could set { "start:test": "npm test" }
in the scripts section of your package.json as shown above, so that if you execute npm start
when NODE_ENV=test
, npm test
will eventually get spawned.
Custom scripts other than start can also be provided in package.json. The same applies to custom NODE_ENV
too. Please refer to more examples below.
In short, in the context of by-node-env, the environment variable NODE_ENV
acts as a switch to select appropriate scripts in package.json for execution.
NODE_ENV
By design, by-node-env must resolve NODE_ENV
ahead of starting your application to select appropriate scripts in package.json for execution, at the same time set the resolved NODE_ENV
as process.env.NODE_ENV
in your application runtime.
The priority order of resolving NODE_ENV
is as follows:
-
Environment variable.
-
.env file in the project root directory.
-
Defaults to development
.
Whichever NODE_ENV
found first takes precedence.
by-node-env will only set process.env.NODE_ENV
of your application to NODE_ENV
it resolved. Other environment variables will be passed as is to your application in process.env
. If a .env file is present in your project root directory, all entries except NODE_ENV
are ignored.
In other words, by-node-env will not manipulate your application's environment variables except NODE_ENV
.
Example 1
Example 1: .env
NODE_ENV=production
Example 1: package.json
{
"scripts": {
// This will run "start:production" since .env file is present and NODE_ENV is defined in it.
"start": "by-node-env",
"start:development": "ts-node .",
"start:production": "ts-node-dev ."
}
}
Example 2
Example 2: package.json
{
// Processes spawned by by-node-env inherit environment-specific variables, if defined.
"by-node-env": {
"production": {
"DOCKER_USER": "my",
"DOCKER_REPO": "project"
}
},
"scripts": {
// If NODE_ENV is missing, defaults to "development".
"build": "by-node-env",
"build:development": "webpack -d --watch",
"build:production": "webpack -p",
"build:staging": "webpack -p",
// Deployment will not work unless NODE_ENV=production is explicitly set.
"deploy": "by-node-env",
"predeploy:production": "docker build -t ${DOCKER_USER}/${DOCKER_PROJECT} .",
"deploy:production": "docker push ${DOCKER_USER}/${DOCKER_PROJECT}",
// "npm start" is _the_ command to start the server across all environments.
"start": "by-node-env",
"start:development": "npm run build:development",
"prestart:production": "npm run build",
"start:production": "start-cluster build/server/server.js",
"prestart:staging": "npm run build",
"start:staging": "start-cluster build/server/server.js",
// Explicitly set NODE_ENV, which is helpful in CI.
"test": "NODE_ENV=test by-node-env",
"test:test": "mocha"
}
}
Notes
-
by-node-env is essentially a clone of per-env with some notable fixes:
- .env (
NODE_ENV
only) support. - pnpm compatibility.
- Windows compatibility.
- Yarn compatibility.
-
The .env file is parsed using dotenv.
-
This package might support more .env files in the future, as documented by create-react-app here.
-
Option to specify a custom file path for the .env file is not yet implemented, please raise an issue or PR if you need this feature.
Contributing
Encounter bugs or having new suggestions?
Issues, comments, and PRs are always welcomed!