On this page

Three commands cover almost everything you do day to day: build once, rebuild on change, or serve. This guide covers each of them, then how to tell the CLI which configuration to run and how to build without one at all.

build compiles once and exits. It is the default command, so these two are identical:

npx webpack
npx webpack build

Positional arguments are treated as entries, and flags map onto configuration options:

Use this in CI and in your npm run build script. It exits non-zero when the build fails, so a broken build stops the pipeline. See exit codes for what each status means.

watch runs the same build, then keeps the process alive and recompiles whenever a file in the dependency graph changes:

Rebuilds are much faster than the first build because webpack keeps the module graph in memory. npx webpack --watch does the same thing through the watch option, and watchOptions tunes the polling and debouncing behavior.

Reach for watch when something other than a browser consumes the output — a server process, an extension host, an Electron main process. If you are building for a browser, serve is usually the better fit.

serve starts webpack-dev-server, which watches your files, keeps the bundles in memory, and serves them over HTTP with live reloading and Hot Module Replacement:

The dev server is a separate package, so install it first:

Because it needs its own settings as well as webpack's, webpack serve accepts the union of both flag sets. The development guide walks through a realistic setup.

Without --config, the CLI discovers a configuration file by convention. Pass one explicitly when the file lives elsewhere or has a different name:

A configuration file can export an array of configurations, which webpack builds in parallel. Give each one a name and you can build a single configuration on demand:

export default [
  {
    name: 'client',
    entry: './src/client.js',
    output: { filename: 'client.js' },
    mode: 'development',
  },
  {
    name: 'server',
    entry: './src/server.js',
    output: { filename: 'server.js' },
    target: 'node',
    mode: 'development',
  },
];

The flag can be repeated to select a subset:

--merge combines two or more configuration files with webpack-merge, with later files winning on conflicts:

This is a way to keep a shared base configuration separate from per-environment overrides without writing any merge code yourself. The production guide uses the same split.

--extends does the same job from the other direction: instead of listing every file on the command line, a configuration declares the base it builds on.

The equivalent extends option inside the configuration file itself is usually tidier, since the relationship travels with the file rather than with the invocation.

For a quick one-off bundle, entry and output can come straight from the command line:

--entry accepts several values, each becoming a separate entry point:

Warning

--entry adds to the entries already defined in your configuration. Use --entry-reset first when you want to replace them instead of appending to them.

Tip

Prefer the webpack [command] --entry-reset [entries...] [options] shape. Some options accept multiple values, so a trailing positional argument can be swallowed by the preceding flag: webpack --target node ./entry.js is parsed as target: ['node', './entry.js'].

Given this project:

.
├── dist
├── index.html
└── src
    ├── index.js
    ├── index2.js
    └── others.js

bundling one entry:

produces a single bundle whose graph starts at index.js:

asset main.js 142 bytes [compared for emit] [minimized] (name: main)
./src/index.js 30 bytes [built] [code generated]
./src/others.js 1 bytes [built] [code generated]
webpack 5.109.2 compiled successfully in 187 ms

while passing two files makes each one its own entry point:

--output-path maps to output.path; the emitted filenames still come from output.filename and default to [name].js.

This is fine for experiments and one-liners. As soon as you need loaders, plugins, or more than a couple of options, move to a configuration file.

Some builds need Node.js itself to be configured — a larger heap, a preloaded module, a custom loader hook. Those are not webpack flags, so pass them through NODE_OPTIONS:

Several options can be combined in one value: