webpack 4: mode and optimization

webpack adds a mode option. What does that mean?

So webpack 4 added a mode option. And it’s required. (Actually it’s not required but it will warn you if you omit it.)

webpack 4 now ships with two sets of defaults. development and production. These are the two values to which mode can be set to.

The development defaults will give you the best* development experience focusing on:

  • Tooling for in browser debugging
  • Fast incremental compilation for a fast development cycle
  • Useful error messages at runtime

(* Actually this depends on your use case, we try to cover the most common one here)

While the production defaults will give you a set of defaults useful for deploying your application, focusing on:

  • Small output size
  • Fast code at runtime
  • Omitting development-only code
  • Not exposing source code or file paths
  • Easy to use output assets

The last bullet point is pretty important. It basically means production gives you well optimized assets, but not perfectly optimized assets. There are additional optimizations possible, but they would make the result more difficult to use. These optimizations are intentionally omitted because here we value getting started experience higher than perfect optimization. Most of the additional optimization are only relevant for large applications anyway.

With the new mode option we tried to reduce the required configuration for a useful build. We tried to cover the common use cases with these defaults.

But from our experience we also know that defaults are not for everyone. Each team has different needs, sometimes because of legacy stuff, sometimes because of personal preferences, sometimes because of special applications or sometimes because they don’t believe common best practices. Many people do want to change defaults to adapt to own use cases. We got you covered. Adding mode doesn’t mean that we remove configuration. Everything is still configurable. We actually made most of the internal optimization steps configurable (you can now disable them).

mode is implemented by setting default values to configuration options. No special behavior is done by mode which isn’t possible via other configuration option.

The next part will go deeper into the configuration options affected by mode and other added options:


Defaults to eval in development mode. Elsewise no devtool is used.

The eval devtool doesn’t give the best quality, but has a very good performance. That’s the trade-off we choose here. Take a look at the documentation for more options which result in better quality SourceMaps.

📉📉📉 slow, bundle size

📈📈📈 improved debugging


Enabled in development mode. Elsewise disabled.

Caches modules and avoid rebuilding them when unchanged.

In memory caching is only useful in watch mode and we assume you are using watch mode in development. The memory footprint is lower without caching.

📉 memory footprint

📈📈📈 faster incremental builds


Enabled when cache is enabled. Elsewise disabled.

Caches resolved dependencies to avoid re-resolving them.

📉 memory footprint, cache entry could be wrong

📈📈 faster incremental builds


Enabled in development mode. Elsewise disabled.

These extra comment are useful for debugging, especially with the eval devtool.

📉 bundle size, leak path info

📈 improved readability of generated code


Enabled in production mode. Elsewise disabled.

The size limits are only useful on minimized assets and it has a performance cost. So it’s only enabled in production mode.

📉 algorithmic cost

📈 warning about bundle size


Always enabled.

Modules are removed from chunks when they are already available in all parent chunk groups. This reduces asset size. Smaller assets also result in faster builds since less code generation has to be performed.

📉📉 algorithmic cost

📈📈📈 bundle size


Always enabled.

Empty chunks are removed. This reduces load in filesystem and results in faster builds.

📉 algorithmic cost

📈📈📈 fewer requests


Always enabled.

Equal chunks are merged. This results in less code generation and faster builds.

📉 algorithmic cost

📈📈📈 fewer requests and downloads


Enabled in production mode. Elsewise disabled.

Chunks which are subsets of other chunks are determined and flagged in a way that subsets don’t have to be loaded when the bigger chunk has been loaded.

📉 algorithmic cost

📈📈 fewer requests and downloads


Enabled in production mode. Elsewise disabled.

Give more often used ids smaller (shorter) values.

📉 algorithmic cost

📈 bundle size


Always enabled.

Determine exports for each module when possible. This information is used by other optimizations or code generation. I. e. to generate more efficient code for export * from.

📉 algorithmic cost

📈 bundle size, requirement for other optimizations


Enabled in production mode. Elsewise disabled.

Determine used exports for each module. This depends on optimization.providedExports. This information is used by other optimizations or code generation. I. e. exports are not generated for unused exports, export names are mangled to single char identifiers when all usages are compatible. DCE in minimizers will benefit from this and can remove unused exports.

📉📉 algorithmic cost

📈📈 bundle size


Enabled in production mode. Elsewise disabled.

Recognise the sideEffects flag in package.json or rules to eliminate modules. This depends on optimization.providedExports and optimization.usedExports. These dependencies have a cost, but eliminating modules has positive impact on performance because of less code generation. It depends on your codebase. Try it for possible performance wins.

📉 algorithmic cost

📈📈📈 bundle size, less code generation


Enabled in production mode. Elsewise disabled.

Tries to find segments of the module graph which can be safely concatenated into a single module. Depends on optimization.providedExports and optimization.usedExports.

📉📉📉 additional parsing, scope-analysis and identifier renaming (performance)

📈📈📈 runtime performance and bundle size


Always enabled.

Finds modules which are shared between chunk and splits them into separate chunks to reduce duplication or separate vendor modules from application modules.

📉 algorithmic cost, additional requests

📈📈📈 less code generation, better caching, less download


Always enabled.

Create a separate chunk for the webpack runtime code and chunk manifest. This chunk should be inlined into the HTML

📉 bigger HTML file

📈 better caching


Enabled in production mode. Elsewise disabled.

Don’t write output assets when compilation errors.

📉 unable to use working part of the application

📈 no broken bundles


Enabled in development mode. Elsewise disabled.

Instead of numeric ids, give modules useful names.

📉 bundle size

📈 better error reporting and debugging


Enabled in development mode. Elsewise disabled.

Instead of numeric ids, give chunks useful names.

📉 bundle size

📈 better error reporting and debugging


Defaults to the mode value: development or production.

Defines the process.env.NODE_ENV constant to a compile-time-constant value. This allows to remove development only code from code.

📉 Code in development is different from code in production

📈📈 bundle size, runtime performance


Enabled in production mode. Elsewise disabled.

Use the minimizer (optimization.minimizer, by default uglify-js) to minimize output assets.

📉📉📉 slow

📈📈📈 bundle size


Enabled with in-file records are used. Elsewise disabled.

Identifiers used in records are relative to context directory.

📉 slow

📈 records are independent of directory