FAQ

This is a collection of common questions about esbuild. You can also ask questions on the GitHub issue tracker.

Why is esbuild fast?

Several reasons:

Each one of these factors is only a somewhat significant speedup, but together they can result in a bundler that is multiple orders of magnitude faster than other bundlers commonly in use today.

Benchmark details

Here are the details about each benchmark:

JavaScript benchmark
esbuild
0.37s
parcel 2
30.50s
rollup + terser
32.07s
webpack 5
39.70s
0s
10s
20s
30s
40s

This benchmark approximates a large JavaScript codebase by duplicating the three.js library 10 times and building a single bundle from scratch, without any caches. The benchmark can be run with make bench-three in the esbuild repo.

Bundler Time Relative slowdown Absolute speed Output size
esbuild 0.37s 1x 1479.6 kloc/s 5.80mb
parcel 2 30.50s 80x 17.9 kloc/s 5.87mb
rollup + terser 32.07s 84x 17.1 kloc/s 5.81mb
webpack 5 39.70s 104x 13.8 kloc/s 5.84mb

Each time reported is the best of three runs. I'm running esbuild with --bundle --minify --sourcemap. I used the @rollup/plugin-terser plugin because Rollup itself doesn't support minification. Webpack 5 uses --mode=production --devtool=sourcemap. Parcel 2 uses the default options. Absolute speed is based on the total line count including comments and blank lines, which is currently 547,441. The tests were done on a 6-core 2019 MacBook Pro with 16gb of RAM and with macOS Spotlight disabled.

TypeScript benchmark
esbuild
0.10s
parcel 2
8.18s
webpack 5
15.96s
0s
5s
10s
15s

This benchmark uses the old Rome code base (prior to their Rust rewrite) to approximate a large TypeScript codebase. All code must be combined into a single minified bundle with source maps and the resulting bundle must work correctly. The benchmark can be run with make bench-rome in the esbuild repo.

Bundler Time Relative slowdown Absolute speed Output size
esbuild 0.10s 1x 1318.4 kloc/s 0.97mb
parcel 2 8.18s 82x 16.1 kloc/s 0.97mb
webpack 5 15.96s 160x 8.3 kloc/s 1.27mb

Each time reported is the best of three runs. I'm running esbuild with --bundle --minify --sourcemap --platform=node. Webpack 5 uses ts-loader with transpileOnly: true and --mode=production --devtool=sourcemap. Parcel 2 uses "engines": "node" in package.json. Absolute speed is based on the total line count including comments and blank lines, which is currently 131,836. The tests were done on a 6-core 2019 MacBook Pro with 16gb of RAM and with macOS Spotlight disabled.

The results don't include Rollup because I couldn't get it to work for reasons relating to TypeScript compilation. I tried @rollup/plugin-typescript but you can't disable type checking, and I tried @rollup/plugin-sucrase but there's no way to provide a tsconfig.json file (which is required for correct path resolution).

Upcoming roadmap

These features are already in progress and are first priority:

These are potential future features but may not happen or may happen to a more limited extent:

After that point, I will consider esbuild to be relatively complete. I'm planning for esbuild to reach a mostly stable state and then stop accumulating more features. This will involve saying "no" to requests for adding major features to esbuild itself. I don't think esbuild should become an all-in-one solution for all frontend needs. In particular, I want to avoid the pain and problems of the "webpack config" model where the underlying tool is too flexible and usability suffers.

For example, I am not planning to include these features in esbuild's core itself:

I hope that the extensibility points I'm adding to esbuild (plugins and the API) will make esbuild useful to include as part of more customized build workflows, but I'm not intending or expecting these extensibility points to cover all use cases. If you have very custom requirements then you should be using other tools. I also hope esbuild inspires other build tools to dramatically improve performance by overhauling their implementations so that everyone can benefit, not just those that use esbuild.

I am planning to continue to maintain everything in esbuild's existing scope even after esbuild reaches stability. This means implementing support for newly-released JavaScript and TypeScript syntax features, for example.

Production readiness

This project has not yet hit version 1.0.0 and is still in active development. That said, it is far beyond the alpha stage and is pretty stable. I think of it as a late-stage beta. For some early-adopters that means it's good enough to use for real things. Some other people think this means esbuild isn't ready yet. This section doesn't try to convince you either way. It just tries to give you enough information so you can decide for yourself whether you want to use esbuild as your bundler.

Some data points:

Anti-virus software

Since esbuild is written in native code, anti-virus software can sometimes incorrectly flag it as a virus. This does not mean esbuild is a virus. I do not publish malicious code and I take supply chain security very seriously.

Virtually all of esbuild's code is first-party code except for one dependency on Google's set of supplemental Go packages. My development work is done on different machine that is isolated from the one I use to publish builds. I have done additional work to ensure that esbuild's published builds are completely reproducible and after every release, published builds are automatically compared to ones locally-built in an unrelated environment to ensure that they are bitwise identical (i.e. that the Go compiler itself has not been compromised). You can also build esbuild from source yourself and compare your build artifacts to the published ones to independently verify this.

Having to deal with false-positives is an unfortunate reality of using anti-virus software. Here are some possible workarounds if your anti-virus won't let you use esbuild:

Minified newlines

People are sometimes surprised that esbuild's minifier typically changes the character escape sequence \n within JavaScript strings into a newline character in a template literal. But this is intentional. This is not a bug with esbuild. The job of a minifier is to generate as compact an output as possible that's equivalent to the input. The character escape sequence \n is two bytes long while a newline character is one byte long.

For example, this code is 21 bytes long:

var text="a\nb\nc\n";

While this code is 18 bytes long:

var text=`a
b
c
`;

So the second code is fully minified while the first one isn't. Minifying code does not mean putting it all on one line. Instead, minifying code means generating equivalent code that uses as few bytes as possible. In JavaScript, an untagged template literal is equivalent to a string literal, so esbuild is doing the correct thing here.