Passing environment-dependent variables in webpack

There are two basic ways to achieve this.

DefinePlugin

new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),

Note that this will just replace the matches "as is". That's why the string is in the format it is. You could have a more complex structure, such as an object there but you get the idea.

EnvironmentPlugin

new webpack.EnvironmentPlugin(['NODE_ENV'])

EnvironmentPlugin uses DefinePlugin internally and maps the environment values to code through it. Terser syntax.

Alias

Alternatively you could consume configuration through an aliased module. From consumer side it would look like this:

var config = require('config');

Configuration itself could look like this:

resolve: {
    alias: {
        config: path.join(__dirname, 'config', process.env.NODE_ENV)
    }
}

Let's say process.env.NODE_ENV is development. It would map into ./config/development.js then. The module it maps to can export configuration like this:

module.exports = {
    testing: 'something',
    ...
};

I investigated a couple of options on how to set environment-specific variables and ended up with this:

I have 2 webpack configs currently:

webpack.production.config.js

new webpack.DefinePlugin({
  'process.env':{
    'NODE_ENV': JSON.stringify('production'),
    'API_URL': JSON.stringify('http://localhost:8080/bands')
  }
}),

webpack.config.js

new webpack.DefinePlugin({
  'process.env':{
    'NODE_ENV': JSON.stringify('development'),
    'API_URL': JSON.stringify('http://10.10.10.10:8080/bands')
  }
}),

In my code I get the value of API_URL in this (brief) way:

const apiUrl = process.env.API_URL;

EDIT 3rd of Nov, 2016

Webpack docs has an example: https://webpack.js.org/plugins/define-plugin/#usage

new webpack.DefinePlugin({
    PRODUCTION: JSON.stringify(true),
    VERSION: JSON.stringify("5fa3b9"),
    BROWSER_SUPPORTS_HTML5: true,
    TWO: "1+1",
    "typeof window": JSON.stringify("object")
})

With ESLint you need to specifically allow undefined variables in code, if you have no-undef rule on. http://eslint.org/docs/rules/no-undef like this:

/*global TWO*/
console.log('Running App version ' + TWO);

EDIT 7th of Sep, 2017 (Create-React-App specific)

If you're not into configuring too much, check out Create-React-App: Create-React-App - Adding Custom Environment Variables. Under the hood CRA uses Webpack anyway.


You can pass environment variables without additional plugins using --env

Webpack 2-4

webpack --config webpack.config.js --env.foo=bar

Webpack 5+ (without.)

webpack --config webpack.config.js --env foo=bar

Then, use the variable in webpack.config.js:

module.exports = function(env) {
    if (env.foo === 'bar') {
        // do something
    }
}

Further Reading: Webpack 2.0 doesn't support custom command line arguments? #2254


Just another option, if you want to use only a cli interface, just use the define option of webpack. I add the following script in my package.json :

"build-production": "webpack -p --define process.env.NODE_ENV='\"production\"' --progress --colors"

So I just have to run npm run build-production.