esbuild vs SWC in 2026: Comparing the Speed Demons
TL;DR
esbuild and SWC serve different primary purposes — they're more complementary than competing. esbuild (~30M weekly downloads) is both a transformer AND a bundler — it can replace webpack/Rollup for simple apps. SWC (~25M downloads) is primarily a Rust-based transformer used inside other tools (Next.js, Vite, Rspack). If you need a complete bundler, use esbuild or Vite (which uses esbuild). If you need TypeScript compilation in a build pipeline, use SWC.
Key Takeaways
- esbuild: ~30M weekly downloads — SWC: ~25M (npm, March 2026)
- esbuild is a bundler — SWC is a transpiler (big difference)
- Both are written in low-level languages — esbuild in Go, SWC in Rust
- Both are 10-100x faster than Babel — the reason they exist
- SWC is inside Next.js —
next builduses SWC by default since Next.js 12
What Each Tool Does
esbuild: Parses, transforms (TypeScript/JSX → JS), bundles (resolves imports, combines files), and minifies. It's a complete build pipeline in one binary.
SWC: Parses and transforms (TypeScript/JSX → JS). Does NOT bundle (doesn't resolve imports). SWC is a drop-in replacement for Babel specifically.
esbuild: [TypeScript source] → [transform] → [bundle] → [minify] → [output JS]
SWC: [TypeScript source] → [transform] → [output JS] (bundling done by another tool)
esbuild: The Complete Solution
// esbuild as a standalone bundler
import * as esbuild from 'esbuild';
await esbuild.build({
entryPoints: ['src/index.tsx'],
bundle: true, // Follows and bundles all imports
minify: true, // Production minification
target: ['es2020'],
platform: 'browser',
outfile: 'dist/bundle.js',
define: {
'process.env.NODE_ENV': '"production"',
},
external: ['react', 'react-dom'], // Don't bundle React (use CDN)
});
// esbuild as a dev server
await esbuild.serve({
servedir: 'public',
}, {
entryPoints: ['src/index.tsx'],
bundle: true,
outdir: 'public/dist',
});
// esbuild via Vite (under the hood)
// Vite uses esbuild for:
// - TypeScript/JSX transpilation (in dev)
// - Dependency pre-bundling (node_modules)
// - Minification in production
esbuild's speed comes from:
- Written in Go — compiled native code, not interpreted
- Parallelizes work across all CPU cores by default
- No plugins for critical paths — JS plugin API exists but core is pure Go
SWC: The Babel Replacement
// .swcrc — drop-in Babel replacement
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true,
"decorators": true
},
"transform": {
"react": {
"runtime": "automatic"
},
"legacyDecorator": true,
"decoratorMetadata": true
},
"target": "es2020",
"loose": false,
"minify": {
"compress": false,
"mangle": false
}
},
"module": {
"type": "commonjs"
}
}
# SWC CLI — transpile TypeScript files
npx @swc/cli compile src/index.ts -o dist/index.js
# Watch mode
npx @swc/cli compile src/ -d dist/ --watch
SWC's main use case is as a faster alternative to Babel in pipelines where something else handles bundling (webpack, Rspack, etc.).
Where They're Used (Ecosystem)
esbuild is used inside:
- Vite (transpilation + dep pre-bundling)
- tsup (TypeScript library bundler)
- Turbopack (uses esbuild for some transpilation)
- Bun (Bun's bundler is inspired by esbuild)
- Many direct-use CLI tools
SWC is used inside:
- Next.js 12+ (replaces Babel by default)
- Rspack (builtin:swc-loader)
- Parcel 2
- Deno
- Farm (build tool)
Performance Comparison
Transpiling a 1,000-file TypeScript project:
| Tool | Time | Notes |
|---|---|---|
| SWC | ~300ms | Rust, single-file transforms |
| esbuild | ~400ms | Go, includes some bundling overhead |
| Babel | ~15,000ms | JavaScript, single-threaded |
| tsc | ~8,000ms | TypeScript compiler (type checking included) |
Both are 30-50x faster than Babel for transpilation. For bundling, esbuild has no equivalent in SWC.
TypeScript Type Checking
This is a critical distinction: neither esbuild nor SWC performs TypeScript type checking.
# Both transpile TypeScript but strip types without checking
# This is a feature, not a bug — they're faster because of it
# Separate type checking step required:
tsc --noEmit # Check types without emitting files
# Typical build pipeline:
# 1. tsc --noEmit (type check — slow but thorough)
# 2. esbuild/SWC/Vite (transpile + bundle — fast)
Run tsc --noEmit in your CI pipeline and use esbuild/SWC for the actual compilation.
Direct Usage Decision Tree
Do you need bundling (combining imports into fewer files)?
YES → Use esbuild directly (or Vite, which uses esbuild)
NO → Use SWC for transpilation only
Are you inside a framework?
Next.js → SWC is already configured, don't touch it
Vite → esbuild is already configured, don't touch it
webpack → Consider swc-loader or babel-loader-with-esbuild
Building a library (not an app)?
→ Use tsup (wraps esbuild, great DX for lib builds)
→ Or tsc for type checking + esbuild for transpilation
Compare esbuild and SWC package health on PkgPulse.
See the live comparison
View esbuild vs. swc on PkgPulse →