Get StartedContribute


Edit this Page  

webpack-dev-server can be used to quickly develop an application. See the "How to Develop?" to get started.

This page describes the options that effect the behavior of webpack-dev-server (short: dev-server).

Options that are compatible with webpack-dev-middleware have 🔑 next to them.



This set of options is picked up by webpack-dev-server and can be used to change it's behavior in various ways. Here's a simple example that gzips and serves everything from our dist/ directory:

devServer: {
  contentBase: path.join(__dirname, "dist"),
  compress: true,
  port: 9000

When the server is started, there will be a message prior to the list of resolved modules:

webpack result is served from /build/
content is served from dist/

that will give some background on where the server is located and what it's serving.

If you're using dev-server through the Node.js API, the options in devServer will be ignored. Pass the options as a second parameter instead: new WebpackDevServer(compiler, {...}).

devServer.publicPath 🔑


The bundled files will be available in the browser under this path.

Imagine that the server is running under http://localhost:8080 and output.filename is set to bundle.js. By default the publicPath is "/", so your bundle is available as http://localhost:8080/bundle.js.

The publicPath can be changed so the bundle is put in a directory:

publicPath: "/assets/"

The bundle will now be available as http://localhost:8080/assets/bundle.js.

Make sure publicPath always starts and ends with a forward slash.

It is also possible to use a full URL. This is necessary for Hot Module Replacement.

publicPath: "http://localhost:8080/assets/"

The bundle will also be available as http://localhost:8080/assets/bundle.js.

It is recommended that devServer.publicPath is the same as output.publicPath.

devServer.quiet 🔑


With quiet enabled, nothing except the initial startup information will be written to the console. This also means that errors or warnings from webpack are not visible.

quiet: true

devServer.noInfo 🔑


With noInfo enabled, messages like the webpack bundle information that is shown when starting up and after each save, will be hidden. Errors and warnings will still be shown.

noInfo: true

devServer.stats 🔑

string object

This option lets you precisely control what bundle information gets displayed. This can be a nice middle ground if you want some bundle information, but not all of it.

There are some presets: none, errors-only, minimal and verbose. Use them like this:

stats: "errors-only"

You can control this even more granularly:

stats: {
  chunks: false,
  hash: false

The available options are: hash, version, timings, assets, chunks, modules, reasons, children, source, errors, errorDetails, warningsand publicPath.

This option has no effect when used with quiet or noInfo.

devServer.watchOptions 🔑


Control options related to watching the files.

You can control how many milliseconds webpack will wait before re-compiling if no additional change was detected. If you want to wait one second, set it like this:

watchOptions: {
  aggregateTimeout: 1000

For some systems, watching many file systems can result in a lot of CPU or memory usage. If this is the case, it is possible to exclude a huge folder like node_modules:

watchOptions: {
  ignored: /node_modules/

webpack uses the file system to get notified of file changes. In some cases this does not work. For example, when using Network File System (NFS). Vagrant also has a lot of problems with this. In these cases, use polling:

watchOptions: {
  poll: true

If this is too heavy on the file system, you can change this to an integer to set the interval in milliseconds.

devServer.headers 🔑


Adds headers to all requests:

headers: {
  "X-Custom-Foo": "bar"

devServer.lazy 🔑


When lazy is enabled, the dev-server will only compile the bundle when it gets requested. This means that webpack will not watch any file changes. We call this lazy mode.

lazy: true
watchOptions will have no effect when used with lazy mode.
If you use the CLI, make sure inline mode is disabled.

devServer.filename 🔑


This option lets you reduce the compilations in lazy mode. By default in lazy mode, every request results in a new compilation. With filename, it's possible to only compile when a certain file is requested.

If output.filename is set to bundle.js and filename is used like this:

lazy: true,
filename: "bundle.js"

It will now only compile the bundle when /bundle.js is requested.

filename has no effect when used without lazy mode.


string array

Tell the server where to serve content from. This is only necessary if you want to serve static files. output.publicPath will be used to determine where the bundles should be served from, and takes precedence.

By default it will use your current working directory to serve content, but you can modify this to another directory:

contentBase: path.join(__dirname, "public")

Note that it is recommended to use an absolute path.

It is also possible to serve from multiple directories:

contentBase: [path.join(__dirname, "public"), path.join(__dirname, "assets")]


It is possible to configure advanced options for serving static files from contentBase. See the Express documentation for the possible options. An example:

staticOptions: {
  redirect: false
This only works when using contentBase as a string.



Enable webpack's Hot Module Replacement feature:

hot: true
Add various other steps needed for this to work. (From my experience, and the current docs it looks like other steps are needed here - not like in the cmd line where it's just a flag)

devServer.inline - CLI only


Toggle between the dev-server's two different modes. By default the application will be served with inline mode enabled. This means that a script will be inserted in your bundle to take care of live reloading, and build messages will appear in the browser console.

It is also possible to use iframe mode, which uses an <iframe> under a notification bar with messages about the build. To switch to iframe mode:

inline: false
Inline mode is recommended when using Hot Module Replacement.


boolean object

When using the HTML5 History API, the index.html page will likely have be served in place of any 404 responses. Enable this by passing:

historyApiFallback: true

By passing an object this behavior can be controlled further using options like rewrites:

historyApiFallback: {
  rewrites: [
    { from: /^\/$/, to: '/views/landing.html' },
    { from: /^\/subpage/, to: '/views/subpage.html' },
    { from: /./, to: '/views/404.html' }

When using dots in your path (common with Angular), you may need to use the disableDotRule:

historyApiFallback: {
  disableDotRule: true

For more options and information, see the connect-history-api-fallback documentation.



Enable gzip compression for everything served:

compress: true

devServer.host - CLI only


Specify a host to use. By default this is localhost. If you want your server to be accessible externally, specify it like this:

host: ""

devServer.port - CLI only


Specify a port number to listen for requests on:

port: 8080

devServer.public - CLI only


When using inline mode and you're proxying dev-server, the inline client script does not always know where to connect to. It will try to guess the URL of the server based on window.location, but if that fails you'll need to use this.

For example, the dev-server is proxied by nginx, and available on myapp.test:

public: "myapp.test:80"



Proxying some URLs can be useful when you have a separate API backend development server and you want to send API requests on the same domain.

The dev-server makes use of the very powerful http-proxy-middleware package. Checkout its documentation for more advanced usages.

With a backend on localhost:3000, you can use this to enable proxying:

proxy: {
  "/api": "http://localhost:3000"

A request to /api/users will now proxy the request to http://localhost:3000/api/users.

If you don't want /api to be passed along, we need to rewrite the path:

proxy: {
  "/api": {
    target: "http://localhost:3000",
    pathRewrite: {"^/api" : ""}

A backend server running on HTTPS with an invalid certificate will not be accepted by default. If you want to, modify your config like this:

proxy: {
  "/api": {
    target: "https://other-server.example.com",
    secure: false

Sometimes you don't want to proxy everything. It is possible to bypass the proxy based on the return value of a function.

In the function you get access to the request, response and proxy options. It must return either false or a path that will be served instead of continuing to proxy the request.

E.g. for a browser request, you want to serve a HTML page, but for an API request you want to proxy it. You could do something like this:

proxy: {
  "/api": {
    target: "http://localhost:3000",
    bypass: function(req, res, proxyOptions) {
      if (req.headers.accept.indexOf("html") !== -1) {
        console.log("Skipping proxy for browser request.");
        return "/index.html";



When using inline mode, the console in your DevTools will show you messages e.g. before reloading, before an error or when Hot Module Replacement is enabled. This may be too verbose.

You can prevent all these messages from showing, by using this option:

clientLogLevel: "none"

Possible values are none, error, warning or info (default).

Note that the console will always show bundle errors and warnings. This option only effects the message before it.


boolean object

By default dev-server will be served over HTTP. It can optionally be served over HTTP/2 with HTTPS:

https: true

With the above setting a self-signed certificate is used, but you can provide your own:

https: {
  key: fs.readFileSync("/path/to/server.key"),
  cert: fs.readFileSync("/path/to/server.crt"),
  ca: fs.readFileSync("/path/to/ca.pem"),

This object is passed straight to Node.js HTTPS module, so see the HTTPS documentation for more information.


Contributor to this pageContributor to this pageContributor to this page