· esbuild / swc / typescript

esbuild vs SWC 2026 — Chọn Compiler Nào Cho Dự Án JS

Năm 2026, SWC thắng cuộc đua ecosystem; esbuild giữ ngôi tốc độ standalone. Framework quyết định cho team đang migrate từ Babel hoặc bắt đầu dự án mới.

Bởi · Cập nhật 21 tháng 5, 2026

2.733 từ · 14 phút đọc

Chọn SWC nếu bạn đang dùng Next.js, migrate từ webpack, hoặc muốn đặt cược vào Turbopack. Chọn esbuild nếu bạn cần một bundler đầy đủ cho dự án mới, library, hoặc CLI — không có Babel plugin tuỳ chỉnh, tốc độ tối đa. Nếu bạn đang dùng Vite, câu trả lời năm 2026 là cả hai đều không cần chọn: Rolldown đảm nhận phần pre-bundling dependency, với SWC plugin tuỳ chọn cho React transforms.

Đó là kết luận. Phần còn lại là lý lẽ — benchmark, so sánh plugin ecosystem, và chi phí migration — để bạn tự đánh giá xem tình huống của mình có phù hợp không.

Bài viết này dành cho ai

Các developer đang cân nhắc giữa esbuild và SWC cho việc transpile TypeScript/JSX hoặc bundling — đặc biệt là những người đang migrate từ Babel, hoặc đang chọn toolchain cho dự án mới. Nếu bạn đang dùng Vite, hãy bỏ qua và đọc thẳng phần Vite.

Phiên bản đã kiểm thử

esbuild v0.28.0 và @swc/core v1.15.33, cả hai đều là bản mới nhất tính đến tháng 5 năm 2026. Các con số benchmark lấy từ nguồn gốc — FAQ của esbuild, blog hiệu năng chính thức của SWC, và các bài đăng kỹ thuật từ Vercel — trừ khi có ghi chú khác. Phiên bản ecosystem liên quan: Next.js v16, Vite v8.

Điểm khác biệt cơ bản: bundler vs transformer

Trước khi so sánh tốc độ, cần hiểu đúng phân loại.

esbuild là một bundler tích hợp khả năng transpile. Nó resolve import, code-split, tree-shake, và xuất ra production bundle. Một công cụ, toàn bộ pipeline.

SWC chỉ là transformer. Nó compile TypeScript, JSX, và JavaScript hiện đại — nhưng không bundle. Bạn vẫn cần một bundler (webpack, Rollup, Rolldown, hoặc thứ khác) ở trên.

Điều này quan trọng vì “esbuild nhanh hơn SWC” không phải là một so sánh có ý nghĩa. Bạn đang đo hai thứ khác nhau. Câu hỏi đúng là: ở phần mà cả hai đều làm — transpile TypeScript và JSX — thì ai nhanh hơn? Và riêng biệt: bạn có cần bundler không?

Benchmark tốc độ

esbuild so với các bundler truyền thống

Điểm mạnh của esbuild là tốc độ bundle. Theo FAQ chính thức, đo trên benchmark 10 entry point:

Công cụThời gian build
esbuild0.39s
Parcel 214.91s (38×)
Rollup 4 + Terser34.10s (87×)
webpack41.21s (106×)

Các con số này đúng trong thực tế. Tốc độ đến từ khả năng parallelism native của Go, một lần parse AST dùng chung, và toàn bộ quá trình chỉ qua một lần traversal. esbuild không có plugin overhead cho các transform tích hợp sẵn.

SWC vs Babel

Benchmark của SWC (từ swc.rs/blog/perf-swc-vs-babel) đo throughput transform ở các mức concurrency khác nhau:

ConcurrencySWC (ops/sec)Babel (ops/sec)Tỉ lệ
161634.0518.1×
41,70427.2862.4×
1002,1993268.7×

Ở 100 thao tác đồng thời, SWC xử lý 2,199 file mỗi giây trong khi Babel chỉ đạt 32. Khoảng cách càng lớn ở mức concurrency cao vì SWC là Rust native — nút thắt cổ chai của Babel là V8 event loop.

Ngay cả với một file transform đơn lẻ, tỉ lệ vẫn là 18.1×. Trong pipeline build tuần tự, con số đó vẫn có ý nghĩa thực tế.

Hiệu quả thực tế trên Next.js

Khi Next.js 12 ra mắt SWC làm compiler mặc định (thay thế Babel), Vercel đo trên codebase production của mình:

  • Nhanh hơn 17× khi transform
  • Fast Refresh nhanh hơn 3× (hot reload)
  • Build nhanh hơn 5×
  • Minify nhanh hơn 7× so với Terser

Turbopack (dựa trên SWC, bundler mặc định trong Next.js 16 từ tháng 10 năm 2025) đẩy thêm xa hơn:

Đây không phải micro-benchmark. Đây là các phép đo trên ứng dụng Next.js quy mô lớn trong production.

Hệ sinh thái plugin trong thực tế

Tốc độ là một chiều. Chiều còn lại là tool đó có hỗ trợ thứ bạn thực sự cần không.

Plugin esbuild

esbuild có JavaScript plugin API ổn định. Plugin hook vào các pha resolve và load. Trong thực tế, điều này đủ cho các nhu cầu build phổ biến nhất:

  • Path aliases (@/components → src/components)
  • Import SVG (xuất ra React component hoặc data URI)
  • CSS modules
  • Thay thế biến môi trường
  • Custom file loader

Giới hạn cứng: plugin không thể sửa đổi AST. esbuild parse, xử lý, và xuất ra — plugin can thiệp ở ranh giới file, không phải bên trong cây cú pháp. Với những team có custom Babel transform hoạt động trực tiếp trên AST (macro, source-level rewriting, decorator tuỳ chỉnh), đây là điểm chặn. Bạn sẽ phải port logic đó sang loader hoặc tìm hướng tiếp cận khác.

Đây là lựa chọn thiết kế có chủ ý, không phải thiếu sót. Chính giới hạn này giữ cho kiến trúc single-pass của esbuild còn nguyên vẹn. Nếu bạn không cần AST plugin, bạn không phải trả phí gián tiếp đó.

Plugin SWC

SWC có hai mô hình plugin đáng phân biệt rõ:

Transform tích hợp sẵn (Rust, đi kèm với SWC): Nhanh, đã được kiểm chứng kỹ, và bao phủ nhu cầu phổ biến nhất trong React ecosystem:

  • styled-components
  • emotion
  • Jest transform (@swc/jest)
  • Class properties
  • Decorators (stage 2 và 3)
  • Tích hợp Relay GraphQL compiler

Với hầu hết dự án React migrate từ Babel, các built-in đã đủ dùng. Bạn có được tốc độ SWC mà không cần chạm vào Rust.

Wasm plugin (do cộng đồng viết): Bạn compile một Rust transform sang WebAssembly. Cách này cho phép thao tác AST tuỳ ý — nhưng rất khó viết và càng khó bảo trì hơn. Nếu bạn cần custom Wasm plugin, hãy chuẩn bị cho friction setup đáng kể, và kiểm tra kỹ xem compilation target Wasm có ổn định với phiên bản SWC của bạn không.

Trường hợp Babel vẫn chiếm ưu thế

Nếu project của bạn phụ thuộc vào một Babel macro tuỳ chỉnh, một AST transform đặc thù cho domain, hoặc một Babel plugin chưa có tương đương trong SWC, bạn vẫn phải dùng Babel — hoặc phải đầu tư công sức kỹ thuật. Cả hai tool đang thu hẹp khoảng cách này, nhưng không cái nào đạt 100% tương thích Babel plugin.

Trước khi quyết định migrate, hãy kiểm tra Babel config và danh sách plugin thủ công. Map từng Babel plugin sang tương đương trong SWC hoặc built-in — cái nào chưa có tương đương là rủi ro của bạn.

Người dùng Next.js: SWC đã có sẵn rồi

Nếu bạn đang dùng Next.js 12 trở lên, SWC đã là compiler mặc định. Bạn không chọn nó — nó được chọn sẵn cho bạn.

Một bẫy hay gặp: nếu project của bạn có file .babelrc hoặc babel.config.js ở thư mục gốc, Next.js sẽ tự động fallback về Babel. Đây là shim tương thích, không phải khuyến nghị. Fallback về Babel đồng nghĩa bạn mất toàn bộ lợi thế tốc độ của SWC. Hãy kiểm tra thư mục gốc project trước khi giả định SWC đang chạy. Log build của Next.js sẽ in SWC hoặc Babel bên cạnh dòng compiler — hãy kiểm tra một lần.

Next.js 16 (tháng 10 năm 2025) đặt Turbopack làm bundler mặc định cho tất cả ứng dụng. Turbopack xây dựng trên SWC. Chọn SWC ở đây có nghĩa là bạn đang đi cùng chiều với roadmap của Vercel/Next.js, không ngược lại.

Người dùng Vite: câu trả lời năm 2026 là Rolldown

Trước đây, Vite dùng esbuild để pre-bundle dependency (chuyển đổi CJS node_modules sang ESM nhanh chóng) và Rollup cho production build.

Vite v8 đã chuyển sang Rolldown cho việc pre-bundle dependency — một Rust-based bundler được xây dựng bởi VoidZero, team đứng sau Vite. esbuild không còn nằm trong critical path của Vite nữa.

Điều này có nghĩa gì trong thực tế:

  • Bundling: Rolldown lo phần này. Bạn không phải chọn esbuild hay SWC làm bundler.
  • React transforms: @vitejs/plugin-react vẫn dùng Babel bên dưới theo mặc định. Nếu bạn muốn React transforms dựa trên SWC, @vitejs/plugin-react-swc là thay thế trực tiếp — Fast Refresh nhanh hơn khi dev, không cần Babel.

Nếu bạn đang dùng Vite, câu hỏi “esbuild vs SWC” phần lớn thu gọn lại thành: bạn có muốn @vitejs/plugin-react-swc để transform nhanh hơn trong dev mode không? Thường là có, đặc biệt với cây component lớn. Nhưng bạn không thay bundler dù chọn gì.

Nếu bạn đang cân nhắc có nên chuyển từ webpack sang Vite hay không, Vite vs Webpack phân tích chi phí migration và thời điểm đáng để chuyển.

Turbopack và định hướng tương lai

Turbopack là Rust-based bundler của Vercel, được định vị là người kế thừa webpack. Nó dùng SWC làm parser và transformer cốt lõi. Với Next.js 16 mặc định Turbopack cho mọi build, SWC là lớp transform bên dưới thế hệ tiếp theo của build tooling trong React ecosystem. Nếu bạn đang so sánh Turbopack với Vite cho dự án, Turbopack vs Vite có đủ số liệu HMR và build để so sánh trực tiếp.

Hướng phát triển của esbuild thì khác. Evan Wallace đã nói rõ rằng scope tính năng của esbuild là có chủ đích — mục tiêu là một tool ổn định, nhanh, làm tốt việc của nó mà không cần phình to ra. Sự ổn định đó là điểm cộng thực sự với những team muốn một build tool không đổi API bất ngờ. Nhưng điều đó cũng có nghĩa esbuild sẽ không trở thành cốt lõi của một ecosystem integration tương đương Next.js.

Nếu stack của bạn là React + Next.js, SWC là lựa chọn có nhiều momentum nhất. Nếu stack của bạn là greenfield hoặc framework-agnostic, sự ổn định và đơn giản của esbuild là lý lẽ thuyết phục.

Chi phí migration: Babel → SWC vs Babel → esbuild

Babel sang SWC

Ít trở ngại hơn với phần lớn project:

  • @swc/cli đọc file .swcrc có cấu trúc khá gần với các Babel preset phổ biến.
  • Hỗ trợ tích hợp cho các Babel plugin phổ biến nhất: React, TypeScript, decorators, class properties, styled-components, emotion.
  • Rủi ro: Babel plugin tuỳ chỉnh chưa có tương đương trong SWC. Kiểm kê trước khi migrate. Nếu bạn có 3 custom plugin, hãy dự kiến ít nhất một cái sẽ cần workaround.
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": true,
      "decorators": true
    },
    "transform": {
      "react": {
        "runtime": "automatic"
      }
    },
    "target": "es2022"
  },
  "module": {
    "type": "es6"
  }
}

File .swcrc này xử lý TypeScript, TSX, decorators, và React JSX transform mới. Tương đương với @babel/preset-env + @babel/preset-react + @babel/preset-typescript + @babel/plugin-proposal-decorators.

Babel sang esbuild

Thay đổi kiến trúc lớn hơn, tiềm năng tốc độ cao hơn:

  • esbuild thay thế bundler của bạn (webpack, Rollup), không chỉ Babel. Đây là phạm vi migration khác hẳn.
  • Babel plugin ở tầng AST không thể chuyển sang được.
  • Phù hợp nhất: library build, CLI tool, serverless function, hoặc greenfield project nơi bạn kiểm soát toàn bộ pipeline.
// build.mjs
import { build } from 'esbuild';

await build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  platform: 'node',
  target: 'node20',
  outfile: 'dist/index.js',
  format: 'esm',
  sourcemap: true,
});

Script này bundle một TypeScript entry point cho Node 20, xuất ESM, và bao gồm source map. esbuild xử lý TypeScript stripping native — không cần bước tsc riêng (mặc dù bạn vẫn nên có tsc --noEmit trong CI để kiểm tra kiểu, vì cả esbuild lẫn SWC đều không kiểm tra kiểu).

Khi viết và điều chỉnh cấu hình build như thế này, một editor tích hợp AI như Cursor tiết kiệm thời gian đáng kể — API cấu hình của esbuild và SWC có rất nhiều bề mặt, và docs inline giúp tránh phải tra tài liệu reference giữa chừng migration.

Chọn X khi…

Chọn esbuild khi:

  • Bạn đang xây library, CLI, hoặc serverless function từ đầu
  • Bạn muốn một tool duy nhất xử lý cả bundling lẫn transpilation
  • Bạn không có custom Babel AST plugin (hoặc có thể sống thiếu chúng)
  • Bạn không cần toàn bộ plugin ecosystem của webpack

Chọn SWC khi:

  • Bạn đang dùng Next.js (nó đã là compiler của bạn rồi — hãy kiểm tra để chắc chắn bạn không vô tình fallback về Babel)
  • Bạn đang migrate webpack project dần dần (SWC vào thay vị trí compiler, webpack vẫn là bundler)
  • Bạn muốn đi theo roadmap của Turbopack
  • Bạn cần styled-components hoặc emotion transforms mà không cần setup thêm

Dùng Rolldown + SWC plugin tuỳ chọn khi:

  • Bạn đang dùng Vite v8+ — Rolldown lo bundling, @vitejs/plugin-react-swc lo React transforms

Bảng so sánh

esbuild v0.28.0@swc/core v1.15.33
Vai trò chínhBundler + transpilerTranspiler only
Viết bằngGoRust
Hỗ trợ TypeScriptCó (strip types; không type-check)Có (strip types; không type-check)
JSX
DecoratorsStage 3 onlyStage 2 + 3
Plugin APIJS plugins (không mutation AST)Rust/Wasm plugins + built-ins
styled-componentsQua JS pluginTransform tích hợp sẵn
emotionQua JS pluginTransform tích hợp sẵn
Tích hợp ViteThay bằng Rolldown từ v8+Tuỳ chọn qua plugin-react-swc
Mặc định Next.jsKhôngCó (từ Next.js 12)
TurbopackKhôngCó (parser bên dưới)
npm downloads/tuần~71M~25M
Tốc độ bundle0.39s (vs webpack 41.21s)N/A — không phải bundler
Tốc độ transform vs BabelN/A — chưa có benchmark công bố18.1–68.7× (tuỳ concurrency)

Kết luận

Năm 2026, SWC đã thắng cuộc đua ecosystem. Nó là compiler mặc định trong Next.js, là nền tảng của Turbopack, và xử lý transform workload ở tốc độ mà Babel không thể theo kịp ở quy mô lớn. Nếu bạn ở gần Next.js stack, SWC đã là câu trả lời của bạn rồi.

esbuild giữ ngôi tốc độ standalone. Với những dự án greenfield cần một bundler nhanh, gọn, không có di sản Babel, đây vẫn là lựa chọn sạch nhất. Sự ổn định có chủ đích của nó là một tính năng, không phải khoảng trống — một build tool không thay đổi API bất ngờ là điều đáng giá.

Còn với những ai dùng Vite: Rolldown mới là câu chuyện thực sự năm 2026. Câu hỏi esbuild vs SWC hầu như không áp dụng — bạn không chọn cái nào làm bundler, và @vitejs/plugin-react-swc là đòn bẩy hiệu năng thực sự cần quan tâm.

Lưu ý

  • Benchmark 106× webpack của esbuild lấy từ FAQ của esbuild, đo trên workload test của chính họ. Project của bạn có thể có hình dạng khác.
  • Tỉ lệ 68.7× của SWC so với Babel là ở 100 thao tác đồng thời. Ở một thao tác đơn, tỉ lệ là 18.1×. Hãy khớp kỳ vọng concurrency với setup build thực tế của bạn.
  • Cả esbuild lẫn SWC đều không kiểm tra kiểu TypeScript — bạn vẫn cần tsc --noEmit trong CI.
  • Vercel có chương trình affiliate. Toolchew hiện không có affiliate slug Vercel được track; Vercel được nhắc đến ở đây vì đây là thực tế — họ là tổ chức đứng sau Next.js và Turbopack, không phải vì lý do affiliate.
  • Bài viết này có chứa affiliate link đến Cursor (/go/cursor).

Tài liệu tham khảo