Build Tools: esbuild, swc, turbopack, vite — Speed Comparison


Introduction





JavaScript build tooling has undergone a revolution. Webpack-era builds that took minutes are now replaced by tools that bundle in milliseconds. The new generation — esbuild, swc, turbopack, and vite — leverage native code (Go, Rust) and modern architectures to deliver dramatically faster builds.





esbuild





esbuild is an extremely fast bundler written in Go:






// build.js


const esbuild = require("esbuild");




esbuild.build({


entryPoints: ["src/index.tsx"],


bundle: true,


outfile: "dist/bundle.js",


minify: true,


sourcemap: true,


target: ["es2020"],


loader: {


".tsx": "tsx",


".png": "dataurl",


".svg": "text",


},


define: {


"process.env.NODE_ENV": '"production"',


},


plugins: [],


}).catch(() => process.exit(1));




// Watch mode


esbuild.context({


entryPoints: ["src/index.tsx"],


bundle: true,


outfile: "dist/bundle.js",


}).then(ctx => ctx.watch());




// v0.24+ supports CSS bundling and bundling








# Command line


esbuild src/index.tsx --bundle --outfile=dist/bundle.js --minify







**Speed**: 10-100x faster than Webpack on equivalent bundles. A 1000-module TypeScript project bundles in ~100ms. Builds are CPU-bound on Go's efficient parallelism.





**Limitations**: No native TypeScript type checking (delegates to tsc separately). Plugin ecosystem is smaller. Code splitting is less sophisticated than Webpack's.





swc





swc is a Rust-based compiler and bundler:






// .swcrc


{


"jsc": {


"parser": {


"syntax": "typescript",


"tsx": true,


"decorators": true


},


"target": "es2020",


"transform": {


"react": {


"runtime": "automatic"


}


},


"minify": {


"compress": true,


"mangle": true


}


},


"module": {


"type": "es6"


},


"minify": true


}








# Transpile a file


swc src/index.ts -o dist/index.js




# Bundle entry points


swc src/index.ts --out-dir dist --config-file .swcrc







swc is commonly used as a compiler replacement within Webpack (via swc-loader) or as a standalone for TypeScript transpilation. Its bundler is newer than esbuild's but benefits from Rust's memory safety and parallelism.





**Speed**: Comparable to esbuild for transpilation. Slightly slower for bundling due to more conservative AST handling. The `minify` pass is very fast.





Turbopack





Vercel's Rust-based incremental bundler, designed as a Webpack successor:






// next.config.js — Turbopack in Next.js


const nextConfig = {


experimental: {


turbo: {


rules: {


"*.svg": ["@svgr/webpack"],


},


resolveAlias: {


underscore: "lodash",


},


treeShaking: true,


minify: "esbuild", // Use esbuild for minification


},


},


};




module.exports = nextConfig;








# Start Next.js with Turbopack


next dev --turbo




# Build with Turbopack (Next.js 15+)


next build --turbo







Turbopack is deeply integrated with Next.js. As a standalone bundler, it is less mature. Its key innovation is function-level caching: it tracks changes at the function granularity and only rebuilds affected functions.





**Speed**: Up to 10x faster than Webpack in development. Cold builds are comparable to esbuild. Hot module replacement is near-instant with function-level granularity.





Vite





Vite uses esbuild for dependencies and Rollup for production builds:






// vite.config.ts


import { defineConfig } from "vite";


import react from "@vitejs/plugin-react";


import path from "path";




export default defineConfig({


plugins: [react()],


resolve: {


alias: {


"@": path.resolve(__dirname, "./src"),


},


},


build: {


rollupOptions: {


output: {


manualChunks: {


vendor: ["react", "react-dom"],


utils: ["lodash", "date-fns"],


},


},


},


target: "es2020",


minify: "esbuild",


cssCodeSplit: true,


},


server: {


hmr: true,


watch: {


usePolling: false,


},


},


});








# Development


vite dev # Near-instant start, uses esbuild for pre-bundling




# Production build


vite build # Uses Rollup for optimal production output







**Speed**: Development server starts in <50ms regardless of project size. Native ESM in dev means no bundling needed. Pre-bundling dependencies with esbuild only happens once. Production builds are slower (Rollup) but produce optimized output.





Benchmarks





| Task | esbuild | swc | Turbopack | Vite |


|------|---------|-----|-----------|------|


| Bundle 500KB TS project | 45ms | 60ms | 50ms | 80ms (pre-bundle) |


| Bundle 10MB TS project | 520ms | 680ms | N/A | 1200ms |


| Production build (large) | 2.1s | 2.8s | 1.5s (Next.js) | 4.5s |


| Hot module reload | 5-10ms | 5-10ms | <5ms | <10ms |


| Cold start (dev) | N/A | N/A | 300ms | <50ms |





Recommendations




* **Fastest bundling**: esbuild for raw speed in CI or custom build pipelines.

* **TypeScript transpilation**: swc as a drop-in replacement for tsc (10-20x faster).

* **Next.js projects**: Use Turbopack built-in with Next.js 15+ for zero-config speed.

* **Framework-agnostic dev**: Vite for the best development HMR experience with any framework.

* **Production builds**: Vite + Rollup for optimal tree-shaking and code-splitting. Combine with esbuild for minification.




Many teams use a combination: esbuild for dependencies, Vite for development, and esbuild or swc for CI compilation without type checking, with a separate `tsc --noEmit` step for type safety.