Aesthetic fluff image for post. Not partricularly relevant to content.
Photo by Markus Winkler

How to use environment variables in NPM scripts safely across operating systems

If you’re working with JavaScript, particularly Node, in Windows you might have come across this error before:

'NODE_ENV' is not recognized as an internal or external command,
operable program or batch file

The term NODE_ENV might be substituted with something else, but the essence of the problem is that some code is trying to set an environment variable in a non-windowsy way. The most common culprit I’ve seen is NPM scripts. Something that looks similar to this snippet in a package.json file:

"scripts": {
  "build": "NODE_ENV=production webpack"

On Mac OS and Linux this is a very common way to set environment variables, but we need to make a small tweak for this to work on Windows (unless you are using Bash on Windows or another substitute).

Note: You could use --mode=production as a flag for Webpack in particular, but this is just a general common example.

I’m going to show a couple ways to remedy this situation, but if you want my preferred solution without the extra information feel free to skip to the bottom of the article. Also, if you prefer a video I have one here:

Adjusting the script only for Windows

We’ll see why this isn’t the best way to handle this in a moment, but just to get things running, and for general knowledge, you can get the previous script to work on Windows by changing it to this:

"scripts": {
  "build": "set NODE_ENV=production& webpack"

The build script above has some small changes that are very important. The most obvious is the addition of the set keyword at the beginning of the script. This is how you set an environment variable on Windows. The second, more subtle change, is the & appended to the environment variable declaration.

This & is necessary to tell Windows we want to move on to running another command after setting the variable, very similar to the:

npm run build && npm serve format you commonly see in scripts.

IMPORTANT: It is not a mistake that there is no space between production and &. If you were to put a space there, it would set the environment variable to the string "production " with a space at the end.

The problem with the Windows only way

You could stop here in many situations but you have two potential problems before you.

First, anyone using your project on a non-Windows machine essentially has the same problem you just fixed for yourself.

Second, and perhaps more impacting to you, is that any server your scripts run on are likely going to be Linux machines. This means when you deploy your code to your server, none of your scripts will run. Some people opt to just write separate scripts, which works but is a bit clunkier than the common solution, imo.

The best of all worlds: cross-env

The most universal solve, and in my experience the most common in the JS ecosystem, is to install a package in your project:

npm i -D cross-env

This package allows you to use the cross-env command at the beginning of your scripts to make them work across various operating systems. Here’s our previous script adapted:

"scripts": {
  "build": "cross-env NODE_ENV=production webpack"

That’s all it takes, really. You can use that on any old script in your package.json, and if you’d like to know more about what the package can do just head over to the cross-env package readme.