Skip to main content

esbuild vs SWC in 2026: Comparing the Speed Demons

·PkgPulse Team

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.jsnext build uses 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:

  1. Written in Go — compiled native code, not interpreted
  2. Parallelizes work across all CPU cores by default
  3. 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:

ToolTimeNotes
SWC~300msRust, single-file transforms
esbuild~400msGo, includes some bundling overhead
Babel~15,000msJavaScript, single-threaded
tsc~8,000msTypeScript 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.

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.