How to set environment variables from within package.json?
Asked Answered
S

22

610

How to set some environment variables from within package.json to be used with npm start like commands?

Here's what I currently have in my package.json:

{
  ...
  "scripts": {
    "help": "tagove help",
    "start": "tagove start"
  }
  ...
}

I want to set environment variables (like NODE_ENV) in the start script while still being able to start the app with just one command, npm start.

Shantung answered 4/8, 2014 at 5:55 Comment(1)
You can read this answer https://mcmap.net/q/46096/-setting-environment-variables-for-node-to-retrieveJointly
O
751

Set the environment variable in the script command:

...
"scripts": {
  "start": "node app.js",
  "test": "NODE_ENV=test mocha --reporter spec"
},
...

Then use process.env.NODE_ENV in your app.

Note: This is for Mac & Linux only. For Windows refer to the comments.

Overdye answered 23/11, 2014 at 15:38 Comment(23)
Has some one figured out an alternate for windows..?Saltigrade
@Saltigrade Better npm run solves cross-platform compatibility issues. Its config is somewhat clumsy though.Hoecake
@Saltigrade use cross-env and is very easy to use.Infirm
@Saltigrade use set NODE_ENV=test&& mocha --reporter spec - there is no space between the test and && on purpose.Dorison
Thanks @JamiePenney. I had to remove the space before && to get it to work. Why is that? `set NODE_ENV=development&& (nexttask)Dorchester
@Dorchester can't remember sorry, I think it was including the space in the set call?Dorison
cross-env worked in seconds for me. Consider only adding it with --save-dev if you just need it for npm testStavanger
Doesn't work for npm run-script build. Error thrown 'NODE_ENV' is not recognized as an internal or external command, operable program or batch file`Fisher
"test": "NODE_ENV=test mocha --reporter spec" will not work on Windows systems.Homovec
@Dorchester I think you would end up with NODE_ENV set to 'test ' (note the space). No space is a way to avoid that in case you don't want to (or can't) use quotes.Overrun
If you do use cross-env there is no need to include '&&'. Example: cross-env NODE_ENV=test karma startTachyphylaxis
@Saltigrade @jamie-penney env NODE_ENV=test mocha --reporter spec will use the declared environment variable in a natively cross platform fashion, but the key is it is used by npm in an ad hoc and one-time fashion, just for the npm script execution. (It's not set or exported for future reference.) As long as you're running your command from the npm script, there's no issue. Also, the "&&" must be removed when doing it this way.Messy
if you want to use the env var inside the script itself you need to prepend $, for example if you run mode=prod npm run print and you have a script in your package.json called print "print": "echo environment '$mode'" it will print environment 'prod'Parting
@Saltigrade Multiple environment variables can be set on windows like so: "scripts": { "start": "node index.js", "set:env:this:way": "env FIRST=one env SECOND=two node index.js" },Deepfreeze
Note: env ensures that it works across platforms. How? env is not a valid command on Windows.Schnorrer
What is the env you refer to here? Can you post a link?Enchorial
on windows it works like this: scripts: { "testing": "cypress open --env CYPRESS_CypressBaseUrl=localhost:3000"} ( here: npm > 6, node > 13 )Petrel
I want to use a .env file so that I have all of those important details in a single spot, and so I can run the server from the terminal, or from docker, or docker-compose or whatever. Not finding this very helpful...Puggree
As a Windows users (in 2021), you can use WSL (Windows Subsystem for Linux) to run my Node projects locally. This video https://www.youtube.com/watch?v=lOXatmtBb88 explains how to setup VSCode to use the WSL command line instead of PowerShell. This allows you to run projects such as https://github.com/mattcarlotta/nextjs-ssr-kit from Windows. If you look at the package.json script in this example project you will see it sets environment variables within the node commands.Aweather
As what @w.PatrickGale has suggested, to run WSL in vscode. I believe it might be possible to simply run the bash command in cmd to change to a Linux environment too.Inmost
env-cmd is betterZehe
elegant way to have a prod build go through a dev config so I can easily host solid demos locally without having to manually set environment variables. Adding this to a custom NPM script provided a way to do this with one command without significantly changing anything else.Bubaline
Btw to not have to lose your mind over such a dumb bug, if you set the NODE_ENV like that: bash set NODE_ENV=development && ts-node --transpile-only src/index.ts This will actually include a white space as well as the end of the value, fix it by removing the white space: bash set NODE_ENV=development&& ts-node --transpile-only src/index.ts Wasted half an hour debugging this dumb bug lolDasi
D
386

Just use NPM package cross-env. Super easy. Works on Windows, Linux, and all environments. Notice that you don't use && to move to the next task. You just set the env and then start the next task. Credit to @mikekidder for the suggestion in one of the comments here.

From documentation:

{
  "scripts": {
    "build": "cross-env NODE_ENV=production OTHERFLAG=myValue webpack --config build/webpack.config.js"
  }
}

Notice that if you want to set multiple global vars, you just state them in succession, followed by your command to be executed.

Ultimately, the command that is executed (using spawn) is:

webpack --config build/webpack.config.js

The NODE_ENV environment variable will be set by cross-env

Dorchester answered 20/5, 2016 at 22:52 Comment(7)
Triple backslashes can be used to escape required quotes: "test": "cross-env TS_NODE_COMPILER_OPTIONS='{\\\"module\\\":\\\"commonjs\\\"}' mocha"Toehold
Can someone finally help me decide if I should use env or cross-env? On one hand, env doesn't require me to install anything and on the other hand cross-env is more popular. Can someone please confirm if env works on all platforms?Ilocano
@Ilocano env does not work as-is on all platforms, hence the reason for cross-env to exist. Just use cross-env and be done with it.Dorchester
Also, may be used cross-env-shell instead of cross-env. You can read about it here : npmjs.com/package/cross-env#cross-env-vs-cross-env-shellColewort
It doesn't work for the install script though, I am struggling with Playwright to set PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 before running the install of playwright packageGarrard
This seems to work better for install, based on @Teemuk answer: "preinstall": "export PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 || set PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1" The difficulty is that during install, you have no package, and you cannot have an inline script, so you have to find a pure shell solution that works for Windows, in the preinstall command.Garrard
This package is now deprecated. env-cmd is the obvious replacementPenalize
S
90

Because I often find myself working with multiple environment variables, I find it useful to keep them in a separate .env file (make sure to ignore this from your source control). Then (in Linux) prepend export $(cat .env | xargs) && in your script command before starting your app.

Example .env file:

VAR_A=Hello World
VAR_B=format the .env file like this with new vars separated by a line break

Example index.js:

console.log('Test', process.env.VAR_A, process.env.VAR_B);

Example package.json:

{
  ...
  "scripts": {
    "start": "node index.js",

    "env-linux": "export $(cat .env | xargs) && env",
    "start-linux": "export $(cat .env | xargs) && npm start",

    "env-windows": "(for /F \"tokens=*\" %i in (.env) do set %i)",
    "start-windows": "(for /F \"tokens=*\" %i in (.env) do set %i) && npm start",

  }
  ...
}

Unfortunately I can't seem to set the environment variables by calling a script from a script -- like "start-windows": "npm run env-windows && npm start" -- so there is some redundancy in the scripts.

For a test you can see the env variables by running npm run env-linux or npm run env-windows, and test that they make it into your app by running npm run start-linux or npm run start-windows.

Shaddock answered 21/2, 2019 at 16:47 Comment(5)
Very good, it almost did the job for me! I'd like to add a few comments: - You cannot have empty lines in your .env file - Comments in your .env file will break your script - If multiple scripts use the same .env file, you will have to repeat that - I had to remove the space before && for it to work - If you have multiple .env files, it may be a little harder to maintain Your answer inspired me to prepare this suggestion: #25113010Ghirlandaio
I'm not following the env-windows script. The cmd shell won't recognize export nor the xargs.Rudolph
Thanks for the catch @FelipeNMoura and @DerekGreer . Not sure why I thought export $(cat .env | xargs) && set worked on Windows. I re-did the windows script, tested it out, and made edits to my answer.Shaddock
Use export $(cat .env | xargs)&& instead of export $(cat .env | xargs) && to avoid an extra whitespace in the env variables. These spaces won't show up in console.log and can mess up the code(as it did mine)Protasis
This should be the accepted answer.Decree
S
83

I just wanted to add my two cents here for future Node-explorers. On my Ubuntu 14.04 the NODE_ENV=test didn't work, I had to use export NODE_ENV=test after which NODE_ENV=test started working too, weird.

On Windows as have been said you have to use set NODE_ENV=test but for a cross-platform solution the cross-env library didn't seem to do the trick and do you really need a library to do this:

export NODE_ENV=test || set NODE_ENV=test&& yadda yadda

The vertical bars are needed as otherwise Windows would crash on the unrecognized export NODE_ENV command. I don't know about the trailing space, but just to be sure I removed them too.

Sande answered 2/4, 2016 at 12:17 Comment(4)
Did you use &&? NODE_ENV=test yadda means "run yadda, setting NODE_ENV within yadda's environment variables. NODE_ENV=test && yadda means "set NODE_ENV within the local environment, but don't export it, then run yadda." NODE_ENV=test yadda is the preferred approach.Grayson
Sorry that haven't checked my stackoverflow account in a while. But basically silly Windows didn't work using NODE_ENV=test && npm run test or something similar. I made a better solution using process.env["NODE_ENV"] = "testing"; inside my testhelper.js file.Sande
@Sande just to add my two cents too, when you run your command with && you lost your environment variables, setting environment variables without export works on the current command only (which is nothing). to run the command with the env variable without exporting u do: NODE_ENV=test npm run test. Finally the reason it worked after you exported, is because ur variable is now available (exported) in the session, your NODE_ENV without export wasnt doing anything.Naoise
If you want to set multiple envs at once remember that logic operators in both cmd and bash are strictly from left to right, so chains are easily achievable, and If you want to have clean output after execiting such cross env on windows you can do it like so: export NODE_ENV=0 2>nul || set NODE_ENV=0 && export TRIAL_MODE=1 2>nul || set TRIAL_MODE=1 && echo "$NODE_ENV $TRIAL_MODE %NODE_ENV %TRIAL_MODE" Please remember that on Windows cmd env are available after executing statement, so they are not available in one line solutions.Ascidian
I
43

Try this on Windows by replacing YOURENV:

  {
    ...
     "scripts": {
       "help": "set NODE_ENV=YOURENV && tagove help",
       "start": "set NODE_ENV=YOURENV && tagove start"
     }
    ...
  }
Induce answered 29/11, 2018 at 12:42 Comment(6)
I had to remove the space before &&.Raconteur
@KennethSolberg's comment was the final touch that made it work for me (Windows only)Shenitashenk
I too had the space issue. When logging string length I could tell the space is added. I tried escaped quotes - and they were actually stored in the envar. I tried other delimiters to no avail. Removing the space or trimming the value, which feels wrong to me, were the only ways around this issue.Dynode
THE SPACE!!! Man, it literally worked!Sweet
env-cmd package get the .env automaticallyZehe
On windows, I had to use single & instead of double && and it worked for me. e.g. set NODE_ENV=YOURENV & tagove helpStonebroke
G
20

@luke's answer was almost the one I needed! Thanks.

As the selected answer is very straightforward (and correct), but old, I would like to offer an alternative for importing variables from a .env separate file when running your scripts and fixing some limitations to Luke's answer. Try this:

::: .env file :::

# This way, you CAN use comments in your .env files
NODE_PATH="src/"

# You can also have extra/empty lines in it
SASS_PATH="node_modules:src/styles"

Then, in your package json, you will create a script that will set the variables and run it before the scripts you need them:

::: package.json :::

scripts: {
  "set-env": "export $(cat .env | grep \"^[^#;]\" |xargs)",
  "storybook": "npm run set-env && start-storybook -s public"
}

Some observations:

  • The regular expression in the grep'ed cat command will clear the comments and empty lines.

  • The && don't need to be "glued" to npm run set-env, as it would be required if you were setting the variables in the same command.

  • If you are using yarn, you may see a warning, you can either change it to yarn set-env or use npm run set-env --scripts-prepend-node-path && instead.

Different environments

Another advantage when using it is that you can have different environment variables.

scripts: {
  "set-env:production": "export $(cat .production.env | grep \"^[^#;]\" |xargs)",
  "set-env:development": "export $(cat .env | grep \"^[^#;]\" |xargs)",
}

Please, remember not to add .env files to your git repository when you have keys, passwords or sensitive/personal data in them!

Ghirlandaio answered 6/4, 2020 at 3:2 Comment(2)
The export $(cat .env | grep \"^[^#;]\" |xargs) command works only if it is in the same script as my main script. This would work: export $(cat .env | grep \"^[^#;]\" |xargs) && docker exec -it ${MY_VARIABLE}_wp sh. But this won't: npm run set-env && docker exec -it ${MY_VARIABLE}_wp sh.Venlo
I couldn't able to run the grep command above. So I used egrep. export $(cat .env | egrep '^[^#]' | xargs)Aubervilliers
A
17

For a larger set of environment variables or when you want to reuse them you can use env-cmd.

As a plus, the .env file would also work with direnv.

./.env file:

# This is a comment
ENV1=THANKS
ENV2=FOR ALL
ENV3=THE FISH

./package.json:

{
  "scripts": {
    "test": "env-cmd mocha -R spec"
  }
}
Ange answered 25/7, 2019 at 11:43 Comment(5)
how do you use ENV1 in the script?Boony
The usual process.env.ENV1Amorphism
but, inside the package.json? i had read that is impossible(?)Boony
I don't understand. Why would you do that?Amorphism
maybe is a silly aproach, but I had update the macOs Catalina and now the command mongodb is not working, so I need to specify the data/folder mongod --dbpath ~/data/db. I want to run something like npm mongodb and that will get the environment variable dbpath and run the mondodb just as always... and.. i want to share it with other members.Boony
K
17

UPDATE: This solution may break in npm v7 due to npm RFC 21

CAVEAT: no idea if this works with yarn


npm (and yarn) passes a lot of data from package.json into scripts as environment variables. Use npm run env to see them all. This is documented in https://docs.npmjs.com/misc/scripts#environment and is not only for "lifecycle" scripts like prepublish but also any script executed by npm run.

You can access these inside code (e.g. process.env.npm_package_config_port in JS) but they're already available to the shell running the scripts so you can also access them as $npm_... expansions in the "scripts" (unix syntax, might not work on windows?).

The "config" section seems intended for this use:

  "name": "myproject",
  ...
  "config": {
    "port": "8010"
  },
  "scripts": {
    "start": "node server.js $npm_package_config_port",
    "test": "wait-on http://localhost:$npm_package_config_port/ && node test.js http://localhost:$npm_package_config_port/"
  } 

An important quality of these "config" fields is that users can override them without modifying package.json!

$ npm run start

> [email protected] start /home/cben/mydir
> node server.js $npm_package_config_port

Serving on localhost:8010

$ npm config set myproject:port 8020
$ git diff package.json  # no change!
$ cat ~/.npmrc
myproject:port=8020

$ npm run start

> [email protected] start /home/cben/mydir
> node server.js $npm_package_config_port

Serving on localhost:8020

See npm config and yarn config docs.
It appears that yarn reads ~/.npmrc so npm config set affects both, but yarn config set writes to ~/.yarnrc, so only yarn will see it :-(

Kaiserdom answered 31/3, 2020 at 15:47 Comment(1)
Note that $npm_package_* variables are no longer automatically placed in the environment since NPM v7, so this will probably break.Pullen
G
15

When the NODE_ENV environment variable is set to 'production' all devDependencies in your package.json file will be completely ignored when running npm install. You can also enforce this with a --production flag:

npm install --production

For setting NODE_ENV you can use any of these methods

method 1: set NODE_ENV for all node apps

Windows :

set NODE_ENV=production

Linux, macOS or other unix based system :

export NODE_ENV=production

This sets NODE_ENV for current bash session thus any apps started after this statement will have NODE_ENV set to production.

method 2: set NODE_ENV for current app

NODE_ENV=production node app.js

This will set NODE_ENV for the current app only. This helps when we want to test our apps on different environments.

method 3: create .env file and use it

This uses the idea explained here. Refer this post for more detailed explanation.

Basically, you create a .env file and run some bash scripts to set them on the environment.

To avoid writing a bash script, the env-cmd package can be used to load the environment variables defined in the .env file.

env-cmd .env node app.js

method 4: Use cross-env package

This package allows environment variables to be set in one way for every platform.

After installing it with npm, you can just add it to your deployment script in package.json as follows:

"build:deploy": "cross-env NODE_ENV=production webpack"
Geffner answered 7/10, 2021 at 11:20 Comment(0)
G
14

This will work in Windows console:

"scripts": {
  "setAndStart": "set TMP=test&& node index.js",
  "otherScriptCmd": "echo %TMP%"
}

npm run aaa

output: test

See this answer for details.

Geisler answered 19/3, 2019 at 10:10 Comment(4)
Should be set TMP=test&& npm run bbb. The space before && will also cound as part of then NODE_ENV stringRabe
@Rabe Shouldn't be the case if you surround it with quotes ".Schlemiel
This work without the space before &&. So "scripts": { "aaa": "set TMP=test&& npm run bbb", "bbb": "echo %TMP%" }Guenzi
@O'DaneBrissett I can't check this right now, feel free to edit the answer if you're sure it works in the Windows console.Geisler
W
11

For single environment variable

 "scripts": {
    "start": "set NODE_ENV=production&& node server.js"
 }

For multiple environment variables

 "scripts": {
    "start": "set NODE_ENV=production&& set PORT=8000&& node server.js"
 }
Wham answered 28/3, 2021 at 6:38 Comment(1)
Answers the question/works, but probably not the best. You may end up including API keys etc in your version control repo, assuming you're including your package.json in your repo.Zenda
S
10

suddenly i found that actionhero is using following code, that solved my problem by just passing --NODE_ENV=production in start script command option.

if(argv['NODE_ENV'] != null){
  api.env = argv['NODE_ENV'];
} else if(process.env.NODE_ENV != null){
  api.env = process.env.NODE_ENV;
}

i would really appreciate to accept answer of someone else who know more better way to set environment variables in package.json or init script or something like, where app bootstrapped by someone else.

Shantung answered 4/8, 2014 at 6:20 Comment(0)
V
10

use git bash in windows. Git Bash processes commands differently than cmd.

Most Windows command prompts will choke when you set environment variables with NODE_ENV=production like that. (The exception is Bash on Windows, which uses native Bash.) Similarly, there's a difference in how windows and POSIX commands utilize environment variables. With POSIX, you use: $ENV_VAR and on windows you use %ENV_VAR%. - cross-env doc

{
  ...
  "scripts": {
    "help": "tagove help",
    "start": "env NODE_ENV=production tagove start"
  }
  ...
}

use dotenv package to declare the env variables

Vlf answered 30/4, 2020 at 14:21 Comment(0)
H
8

Running a node.js script from package.json with multiple environment variables:

  1. package.json file:

    "scripts": {
        "do-nothing": "set NODE_ENV=prod4 && set LOCAL_RUN=true && node ./x.js",
 },

x.js file can be as:

let env     = process.env.NODE_ENV;
let isLocal = process.env.LOCAL_RUN;

console.log("ENV"    , env);
console.log("isLocal", isLocal);
Hysteric answered 6/12, 2022 at 14:54 Comment(0)
D
6
{
  ...
  "scripts": {
    "start": "ENV NODE_ENV=production someapp --options"
  }
  ...
}
Dogfight answered 24/11, 2018 at 11:25 Comment(0)
F
5

Most elegant and portable solution: package.json:

"scripts": {
    "serve": "export NODE_PRESERVE_SYMLINKS_MAIN=1 && vue-cli-service serve"
    },

Under windows create export.cmd and put it somewhere to your %PATH%:

@echo off

set %*
Festa answered 17/9, 2021 at 12:38 Comment(1)
This is simple, but quite nicely done.Retiarius
C
4

If you:

  • Are currently using Windows;
  • Have git bash installed;
  • Don't want to use set ENV in your package.json which makes it only runnable for Windows dev machines;

Then you can set the script shell of node from cmd to git bash and write linux-style env setting statements in package.json for it to work on both Windows/Linux/Mac.

$ npm config set script-shell "C:\\Program Files\\git\\bin\\bash.exe"
Cruciate answered 5/7, 2022 at 5:57 Comment(0)
B
2

Although not directly answering the question I´d like to share an idea on top of the other answers. From what I got each of these would offer some level of complexity to achieve cross platform independency.

On my scenario all I wanted, originally, to set a variable to control whether or not to secure the server with JWT authentication (for development purposes)

After reading the answers I decided simply to create 2 different files, with authentication turned on and off respectively.

  "scripts": {
    "dev": "nodemon --debug  index_auth.js",
    "devna": "nodemon --debug  index_no_auth.js",
  }

The files are simply wrappers that call the original index.js file (which I renamed to appbootstrapper.js):

//index_no_auth.js authentication turned off
const bootstrapper = require('./appbootstrapper');
bootstrapper(false);

//index_auth.js authentication turned on
const bootstrapper = require('./appbootstrapper');
bootstrapper(true);

class AppBootStrapper {

    init(useauth) {
        //real initialization
    }
}

Perhaps this can help someone else

Bettiebettina answered 17/1, 2017 at 3:8 Comment(0)
L
1

You should not set ENV variables in package.json. actionhero uses NODE_ENV to allow you to change configuration options which are loaded from the files in ./config. Check out the redis config file, and see how NODE_ENV is uses to change database options in NODE_ENV=test

If you want to use other ENV variables to set things (perhaps the HTTP port), you still don't need to change anything in package.json. For example, if you set PORT=1234 in ENV and want to use that as the HTTP port in NODE_ENV=production, just reference that in the relevant config file, IE:

# in config/servers/web.js
exports.production = { 
  servers: {
    web: function(api){
      return {
       port: process.env.PORT
      }
    }
  }
}
Lothario answered 4/8, 2014 at 17:14 Comment(4)
great. i think you didn't read my question.. my problem is how to set NODE_ENV not what is use of it.Shantung
Perhaps an alternative way to explain this would be that NODE_ENV (and other environment variables) are part of the environment (hence the name). They are usually properties of the server you are running the application on rather than your application. You can set them manually via the command you exec, ie: NODE_ENV=test npm start or have them set by the shellLothario
I disagree. using a ./config for every environment confines you to using static environments when you deploy your app. This is an outdated philosophy that will not allow you to spin up new types of environments when needed. I.E. for every new environment you want, you will have to add a .config. Setting environment variables at runtime can be a superior option when your tech stack requires more flexibility. I think your ./config would be good for setting up "types" of environments, but your app would be more flexible if you could define things like dsn strings and api endpoints at runtime.Maintenance
@JesseGreathouse - I have a node.js application and I need to set the environment variables at runtime - what file would I set them in?Ferdy
S
1

In addition to use of cross-env as documented above, for setting a few environment variables within a package.json 'run script', if your script involves running NodeJS, then you can set Node to pre-require dotenv/config:

{
  scripts: {
    "eg:js": "node -r dotenv/config your-script.js",
    "eg:ts": "ts-node -r dotenv/config your-script.ts",
    "test":  "ts-node -r dotenv/config -C 'console.log(process.env.PATH)'",
  }
}

This will cause your node interpreter to require dotenv/config, which will itself read the .env file in the present working directory from which node was called.

The .env format is lax or liberal:

# Comments are permitted
FOO=123
BAR=${FOO}
BAZ=Basingstoke Round About

#Blank lines are no problem
Slyviasm answered 4/8, 2022 at 15:55 Comment(0)
F
0

Note : In order to set multiple environment variable, script should goes like this

  "scripts": {
    "start": "set NODE_ENV=production&& set MONGO_USER=your_DB_USER_NAME&& set MONGO_PASSWORD=DB_PASSWORD&& set MONGO_DEFAULT_DATABASE=DB_NAME&& node app.js",
  },
Felicefelicia answered 6/12, 2020 at 6:4 Comment(0)
P
0

Using crossenv is probably your best bet as already answered here.

You might want to try using the new Bun.sh for complex scripts. I've been able to clean up my package.json scripts a lot and I can even use typescript scripts. It's great.

https://bun.sh/docs/cli/run

bun run index.js

"scripts": {
  "start": "bun run src/scripts/index.ts",
  "dev": "bun run --watch src/scripts/index.ts",
  "simple": "cross-env NODE_ENV=production start "
},
Pearcy answered 15/11, 2023 at 15:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.