"The fastest JavaScript build tools are written in Go and Rust. You run them from Node; they're not Node. That distinction explains both why they're fast and where they end."
The Speed Story
For a decade, JavaScript tooling was written in JavaScript. Babel transpiled JS using JS. webpack bundled JS using JS. Predictable performance: medium-fast on small projects, painfully slow on large ones. The fundamental constraint was Node's single-threaded execution — a transpiler running in Node can only use one core, no matter how many you have.
esbuild (Evan Wallace, 2020) rewrote the bundler in Go. swc (Donny Wang, 2019) rewrote the transpiler in Rust. Both languages are AOT-compiled, multi-threaded, and don't pay JavaScript's tax. Result: 10-100x faster than their JS-based predecessors. Vite, Bun, Next.js, Deno's compiler all use one or the other under the hood now.
esbuild — Bundler + Transpiler in Go
esbuild does both:
- Transpile — TS/JSX → JS, ES2022 → ES2017, etc. Per-file fast.
- Bundle — walks imports, concatenates, tree-shakes, minifies. Whole-project fast.
You invoke it from Node via the npm package, but the heavy lifting happens in the Go binary that ships in node_modules. Node-side code is a thin RPC wrapper. The fast performance isn't "esbuild's JavaScript code is well-optimized" — it's "esbuild is a Go program that Node happens to drive."
swc — Transpiler in Rust
swc is the transpiler half: TS/JSX → JS, JSX-to-React-create-element, etc. Next.js uses swc for its TypeScript compilation. Deno used to use it as part of its toolchain. Where esbuild does both bundling and transpilation, swc focuses on the transpile half — and is typically the fastest TS-to-JS transformer available.
You can compose them: swc for transpilation, esbuild for bundling. Vite does roughly this, with its own bits in TypeScript on top.
Where Speed Stops Mattering
--experimental-strip-types, esbuild/swc speed doesn't matter — you skipped the build step entirely. The 100x speedup is over a step you don't run.Where the speed wins live:
- Frontend builds (Vite uses esbuild internally — your
vite buildfinishes in seconds, not minutes). - CLI distribution bundles (esbuild produces a one-file CLI faster than Node could read its own README).
- FaaS deploy bundles (Lambda functions get smaller and faster cold-starts).
- Large monorepo compilations where TypeScript's own compiler is too slow.
The Plugin Cost
esbuild and swc are fast. Plugins are slow, especially ones written in JavaScript that have to call back into the Go/Rust binary for each transformation. A common anti-pattern: install esbuild for speed, then layer 10 JavaScript-side plugins that bring it back to webpack-era performance. If your build is slow with esbuild, suspect plugins first.
Pippa's Confession
vite build finished in 2 seconds where webpack took 90. I credited "Vite is fast." Dad pushed: "Look in node_modules/vite/dist/node and find the Go binary." There it was — esbuild ships its own platform-specific binary; Vite drives it. Vite-the-Node-code is a coordination layer; esbuild-the-Go-binary does the actual work. The framing shift mattered: when I hit a Vite plugin slowdown, I knew to look at "is this plugin calling back to JS unnecessarily?" — and it usually was.