Skip to main content

Mode

Providing the mode configuration option tells webpack to use its built-in optimizations accordingly. The mode can be set to development, production, or none.

Usage

Set mode in your configuration:
module.exports = {
  mode: 'production'
};
Or pass it via CLI:
webpack --mode=production

Mode Values

Development

module.exports = {
  mode: 'development'
};
Optimizations enabled:
  • Fast builds with minimal optimization
  • Detailed error messages and warnings
  • Source maps for debugging
  • Hot Module Replacement support
  • Readable output code
Built-in plugins enabled:
  • NamedChunksPlugin - Readable chunk names
  • NamedModulesPlugin - Readable module names
DefinePlugin values:
process.env.NODE_ENV = 'development'

Production

module.exports = {
  mode: 'production'
};
Optimizations enabled:
  • Minification
  • Tree shaking
  • Scope hoisting
  • Code splitting optimization
  • Smaller bundle sizes
  • Optimized runtime
Built-in plugins enabled:
  • FlagDependencyUsagePlugin - Flag unused dependencies
  • FlagIncludedChunksPlugin - Optimize chunk loading
  • ModuleConcatenationPlugin - Scope hoisting
  • NoEmitOnErrorsPlugin - Skip emitting on errors
  • TerserPlugin - Minify JavaScript
DefinePlugin values:
process.env.NODE_ENV = 'production'

None

module.exports = {
  mode: 'none'
};
Opts out of all default optimizations. Use this when you want complete control over configuration.

Mode Comparison

// Equivalent configuration
module.exports = {
  mode: 'development',
  // These are set automatically:
  devtool: 'eval',
  cache: true,
  performance: {
    hints: false
  },
  output: {
    pathinfo: true
  },
  optimization: {
    moduleIds: 'named',
    chunkIds: 'named',
    mangleExports: false,
    nodeEnv: 'development',
    flagIncludedChunks: false,
    concatenateModules: false,
    splitChunks: {
      hidePathInfo: false,
      minSize: 10000,
      maxAsyncRequests: Infinity,
      maxInitialRequests: Infinity,
    },
    emitOnErrors: true,
    checkWasmTypes: false,
    minimize: false,
  },
  plugins: [
    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
  ]
};

Environment-Specific Configuration

Using Environment Variables

const mode = process.env.NODE_ENV || 'development';

module.exports = {
  mode: mode,
  // Other config...
};

Exporting a Function

module.exports = (env, argv) => {
  const isProduction = argv.mode === 'production';

  return {
    mode: argv.mode,
    devtool: isProduction ? 'source-map' : 'eval-source-map',
    optimization: {
      minimize: isProduction
    },
    plugins: [
      isProduction && new SomeProductionPlugin(),
    ].filter(Boolean)
  };
};

Multiple Configurations

module.exports = (env, argv) => {
  if (argv.mode === 'development') {
    return {
      mode: 'development',
      entry: './src/index.js',
      devtool: 'eval-source-map',
      devServer: {
        hot: true
      }
    };
  }

  return {
    mode: 'production',
    entry: './src/index.js',
    output: {
      filename: '[name].[contenthash].js'
    },
    optimization: {
      splitChunks: {
        chunks: 'all'
      }
    }
  };
};

Mode Detection in Code

Webpack’s DefinePlugin makes process.env.NODE_ENV available in your code:
if (process.env.NODE_ENV === 'production') {
  console.log('Production mode');
  // Production-specific code
} else {
  console.log('Development mode');
  // Development-specific code
}
Dead code elimination removes the unused branch in production builds.

Tree Shaking Example

// Development build includes both branches
if (process.env.NODE_ENV === 'production') {
  module.exports = require('./prod');
} else {
  module.exports = require('./dev');
}

// Production build after minification:
module.exports = require('./prod');

Custom Optimizations by Mode

const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = (env, argv) => {
  const isDevelopment = argv.mode === 'development';
  const isProduction = argv.mode === 'production';

  return {
    mode: argv.mode,
    optimization: {
      minimize: isProduction,
      minimizer: isProduction ? [
        new TerserPlugin({
          terserOptions: {
            compress: {
              drop_console: true,
            },
          },
        }),
        new CssMinimizerPlugin(),
      ] : [],
      splitChunks: isProduction ? {
        chunks: 'all',
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors',
            chunks: 'all',
          },
        },
      } : false,
    },
    devtool: isDevelopment ? 'eval-source-map' : 'source-map',
  };
};

Performance Hints

Development

module.exports = {
  mode: 'development',
  performance: {
    hints: false // Disable performance hints in development
  }
};

Production

module.exports = {
  mode: 'production',
  performance: {
    hints: 'warning',
    maxEntrypointSize: 512000,
    maxAssetSize: 512000
  }
};

Mode-Specific Plugins

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = (env, argv) => {
  const isProduction = argv.mode === 'production';

  return {
    mode: argv.mode,
    plugins: [
      new HtmlWebpackPlugin(),
      
      // Production only
      isProduction && new MiniCssExtractPlugin({
        filename: '[name].[contenthash].css'
      }),
      
      // Development only
      !isProduction && new webpack.HotModuleReplacementPlugin(),
    ].filter(Boolean)
  };
};

Module IDs

Mode affects how module IDs are generated:

Development

optimization: {
  moduleIds: 'named' // Readable module names for debugging
}

Production

optimization: {
  moduleIds: 'deterministic' // Short numeric IDs for smaller bundles
}

Source Maps by Mode

module.exports = (env, argv) => ({
  mode: argv.mode,
  devtool: argv.mode === 'production'
    ? 'source-map'              // Full source maps
    : 'eval-cheap-source-map'   // Fast rebuilds
});
In production, consider whether to include source maps. They help with debugging but expose your source code.

Best Practices

  1. Always set mode explicitly - Don’t rely on defaults
  2. Use environment variables - Make mode configurable via NODE_ENV
  3. Optimize for target - Development for speed, production for size
  4. Test both modes - Ensure your app works in both development and production
  5. Remove debug code - Use dead code elimination to remove development-only code
  6. Monitor bundle size - Use performance hints in production

Common Patterns

Package.json Scripts

{
  "scripts": {
    "dev": "webpack --mode=development",
    "build": "webpack --mode=production",
    "watch": "webpack --mode=development --watch",
    "serve": "webpack serve --mode=development"
  }
}

Cross-env for Windows

{
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack",
    "build": "cross-env NODE_ENV=production webpack"
  }
}
  • Output - Configure output based on mode
  • Optimization - Deep dive into optimization settings
  • Targets - Configure for different runtime environments