75

I have a package.json with following (simplified) content in the scripts key:

...
scripts: {
   "start": "NODE_ENV=${NODE_ENV:=production} node start-app.js",
   "poststart": "echo $NODE_ENV"
}
...

From the command line I can run:

npm start

This will run my start-app.js script and set the process.env.NODE_ENV environment variable to "production". See here for syntax explanation.

The poststart will automatically run after start as described here.

However poststart will not "inherit" the NODE_ENV shell environment variable, so the echo command will not echo anything.

My producation code is a little more complex, but what I am trying to accomplish is passing down the NODE_ENV variable from the "starting point" to dependent scripts. Any suggestions/best practices on how to do that?

I dont want to hardcode the NODE_ENV in the poststart, because I might want to do:

NODE_ENV=development npm start

and I want everyting "down the chain" inherit the same environment.

Community
  • 1
  • 1
Björn
  • 12,587
  • 12
  • 51
  • 70
  • From [what I see](https://docs.npmjs.com/misc/scripts), _he package.json fields are tacked onto the npm_package_ prefix_, so you may want to say `npm_package_node_env`. – fedorqui May 10 '16 at 14:05
  • When running multiple commands you should `export` the variable. `export NODE_ENV=something` – Michael Nov 08 '17 at 01:52

3 Answers3

27

You have a few options:

  • better-npm-run,which can define an env for each command separately
  • Instead of a poststart script, you can concatenate commands for npm like so: "start": "NODE_ENV=${NODE_ENV:=production} node start-app.js && echo $NODE_ENV"
  • Use a process manager in production like pm2. pm2 lets you define environment specific json files with settings such as NODE_ENV. At our company, we successfully run all of our apps in different environments with pm2 (all the while having the same start command)
Mario Tacke
  • 5,378
  • 3
  • 30
  • 49
  • Is the NODE_ENV still avalilable when you echo? I experience that its gone, ref https://www.npmjs.com/package/cross-env#known-limitations – vonGohren Feb 20 '17 at 14:15
  • Correct, with `cross-env` this is not possible. The second example actually assigns an environment variable (not using cross-env). – Mario Tacke Feb 20 '17 at 17:19
  • @MarioTacke I just gave this a test and it **does not assign** a variable. If it is set previous to the `npm start` command, it works (inside a `start` script command). – kaiser Jun 05 '17 at 22:36
  • @kaiser it depends on your environment. Can you outline what does and doesn't work in your case? The above is a `poststart` script. `cross-env` also had breaking changes recently. – Mario Tacke Jun 05 '17 at 22:49
  • I just tested this in a `node:8-alpine` Docker container, running Nodejs v8 and NPM v5 and the variables assigned in the container persist. Anyway, I believe we got one misunderstanding: You talk about assigning a variable, if **it is not yet assigned**, while I understood that it will _override_ previously set variables (`NODE_ENV`), right? – kaiser Jun 05 '17 at 22:55
  • That is correct. It will override a previously set environment variable whether or not it has been set yet. – Mario Tacke Jun 05 '17 at 23:08
13

this is how I did it, first you need to install two dev-dependencies

https://www.npmjs.com/package/env-cmd this load your env var from your file

https://www.npmjs.com/package/cross-env this use environment variable in script

example scripts:

"env-cmd ./.config/prod.env cross-env-shell \"docker volume create $DOCKER_VOLUME\""

this load $DOCKER_VOLUME env var from prod.env

update: starting from env-cmd version 10, you need specify -f flag if you want to use a custom env file path

"env-cmd -f ./.config/prod.env cross-env-shell \"docker volume create $DOCKER_VOLUME\""
Acid Coder
  • 2,047
  • 15
  • 21
  • This almost worked for me, but I had to drop the quotes after cross-env-shell, like so: `"env-cmd -f ./.env cross-env-shell docker compose build app --build-arg NPM_TOKEN=$NPM_TOKEN"` – Kevin Borders Dec 20 '21 at 16:50
-6

If you have small use cased, use better-npm-run. For small cases, it works fine. Somehow if you have a lot of commands and it hard manage. Try, batman-cli. Work well and handle lot of environment-dependent issues

npm i -g batman-cli

xdeepakv
  • 7,835
  • 2
  • 22
  • 32