Benchmarks Bundlers
Vite vs esbuild vs tsup
Cold production builds of a TypeScript library — ESM, minified, no declarations.
Products compared
Tests
Test 1 Time per pass
20 measured passes over the corpus. Box is the middle half of the runs, line is the median, whiskers reach the fastest and slowest pass, dots are every run. (LOWER ms = FASTER)
All 20 samples as a table
| Run | esbuild | Vite | tsup |
|---|---|---|---|
| 1 | 16.8 ms | 163.6 ms | 203.4 ms |
| 2 | 15.9 ms | 161.8 ms | 200.4 ms |
| 3 | 15.7 ms | 169.1 ms | 203.8 ms |
| 4 | 15.0 ms | 168.5 ms | 202.6 ms |
| 5 | 16.5 ms | 171.9 ms | 203.2 ms |
| 6 | 15.6 ms | 175.2 ms | 202.8 ms |
| 7 | 16.4 ms | 170.7 ms | 203.0 ms |
| 8 | 17.3 ms | 171.7 ms | 206.3 ms |
| 9 | 15.9 ms | 170.8 ms | 205.3 ms |
| 10 | 16.7 ms | 184.9 ms | 204.5 ms |
| 11 | 15.6 ms | 175.8 ms | 204.2 ms |
| 12 | 16.2 ms | 172.7 ms | 202.7 ms |
| 13 | 15.4 ms | 171.8 ms | 203.8 ms |
| 14 | 17.1 ms | 169.3 ms | 206.7 ms |
| 15 | 16.2 ms | 173.6 ms | 203.4 ms |
| 16 | 16.5 ms | 169.9 ms | 202.9 ms |
| 17 | 15.3 ms | 167.9 ms | 202.9 ms |
| 18 | 15.5 ms | 167.8 ms | 204.1 ms |
| 19 | 14.9 ms | 169.7 ms | 205.3 ms |
| 20 | 14.7 ms | 170.1 ms | 204.2 ms |
Full report, as hyperfine prints it
Benchmark 1: esbuild 0.28.2fastest
- Time (mean ± σ)
- 16.0 ms ± 0.7 ms
- Range (min … max)
- 14.7 ms … 17.3 ms
- Median
- 15.9 ms 20 runs
Benchmark 2: Vite 8.2.2
- Time (mean ± σ)
- 170.8 ms ± 4.7 ms
- Range (min … max)
- 161.8 ms … 184.9 ms
- Median
- 170.4 ms 20 runs
Benchmark 3: tsup 8.5.1
- Time (mean ± σ)
- 203.8 ms ± 1.4 ms
- Range (min … max)
- 200.4 ms … 206.7 ms
- Median
- 203.6 ms 20 runs
Test conditions: rig, corpus, protocol
- Machine
- MacBook Pro
- Chip
- Apple M2 Max
- Cores
- 12 CPU cores
- Memory
- 96 GB
- OS
- macOS 26.6.2 (arm64)
- Runtime
- Node 24.19.0 (Vite, tsup); esbuild native binary; Bun 1.4.0 harness
- Name
- zod 4.5.4 library source
- Source
github.com/colinhacks/zod@v4.5.4/src- Files
- 124
- Lines
- 36,620
- Size
- 1.30 MB
- Warmups
- 3 unmeasured passes
- Measured
- 20 passes per tool
- Process
- A new CLI process for every measured pass, output directory cleared between passes
- Cache
- Warm filesystem cache after 3 unmeasured passes per candidate
- Output
- Bundled output emitted to a dedicated directory per tool
What did we learn?
esbuild finished in 16 ms; Vite took 170 ms, tsup 204 ms. esbuild built zod in 15.9 ms at the median. Vite took 170.4 ms (10.7x slower); tsup took 203.6 ms (12.8x slower). esbuild and tsup produced byte-identical 426 KB bundles. Vite's output was 482 KB — the difference is almost entirely whitespace that Vite preserves in ES library builds for downstream tree-shaking.
What this does not prove
- Cold builds only — no incremental state, fresh CLI process per pass, warm filesystem cache. No watch mode or hot module replacement timing.
- One corpus: a zero-dependency TypeScript library (zod 4.5.4, 124 files, ~36,600 lines). Application builds with many dependencies, code-splitting, or CSS processing may produce different rankings.
- Build speed says nothing about dev-server experience, plugin ecosystems, or output correctness beyond "it built."
- All three tools use esbuild's minifier, but not identically. Vite delegates bundling to Rolldown (Rust), then runs esbuild for minification — but for ES-format library builds, Vite deliberately disables whitespace minification to preserve `/* @__PURE__ */` annotations for downstream tree-shaking. esbuild and tsup minify fully, including whitespace. Re-minifying Vite's output with `esbuild --minify-whitespace` alone brings it within 1.2% of esbuild's size.
- Declaration file generation (.d.ts) is disabled for all candidates. tsup's `dts` option is off by default; enabling it invokes the TypeScript compiler and would add significant time.
- Times are fresh-process wall clock, including runtime startup and CLI module loading. Measured floors on this rig: `node -e 0` ~24 ms, `vite --version` ~77 ms, `tsup --version` ~35 ms, `esbuild --version` ~6 ms (native binary). The tools' self-reported build timers exclude startup cost.
- tsup is no longer actively maintained. Its README recommends tsdown as a successor. Results are included because tsup remains widely installed.
Rerun it yourself: the runner and this corpus definition are in the repository, and the methodology page covers what every run holds constant. Think a result is wrong? Open an issue with your rig and your samples.