· go / typescript / bun

Go vs TypeScript — lựa chọn ngôn ngữ backend cho năm 2026

Go cho workload CPU song song vượt 50k RPS. TypeScript trên Bun cho API nặng I/O và full-stack team. Thành phần team là yếu tố quyết định năm 2026.

Bởi Ethan

3.050 từ · 16 phút đọc

Nếu bạn đang xây dựng một service mà ngưỡng throughput thực sự quan trọng — duy trì 50k+ RPS, workload xử lý CPU song song, hoặc hàng trăm nghìn goroutine chạy đồng thời — hãy chọn Go. Nếu team bạn đã quen với TypeScript, service thiên về I/O, hoặc bạn cần tuyển dụng nhanh từ một pool ứng viên rộng, TypeScript trên Bun là lựa chọn thực sự, không phải phương án dự phòng. Quyết định năm 2026 không còn xoay quanh throughput thuần túy nữa. Bun đã rút ngắn khoảng cách xuống còn ~10–15% so với Go trên các HTTP benchmark phổ biến. Trục quyết định thực sự là mô hình xử lý đồng thời và thành phần team.

Bài này dành cho ai

Các kỹ sư senior và tech lead đang lựa chọn ngôn ngữ cho một backend service mới trong năm 2026. Đây không phải hướng dẫn học ngôn ngữ. Nếu bạn đang vận hành stack Go hoặc TypeScript hiện có mà không có vấn đề cụ thể về hiệu năng hay vận hành, chi phí chuyển đổi gần như chắc chắn không đáng — dừng ở đây.

Cần nói rõ ngay từ đầu: Node.js không phải điểm so sánh phù hợp trong năm 2026. Nếu stack TypeScript của bạn đang chạy trên Node.js, không sao — nhưng khi đánh giá TypeScript như một thay thế cho Go cho service mới, Bun mới là thứ bạn nên đo. Khoảng cách throughput giữa Go và Node.js là khoảng 2×; giữa Go và Bun là khoảng 10–15%. Đây là hai cuộc trò chuyện hoàn toàn khác nhau.

Nguồn dữ liệu

Tất cả số liệu benchmark đến từ các nguồn gốc:

  • TechEmpower Framework Benchmarks Round 22 (tháng 11 năm 2023) — Fiber v3/Go vs Express/Node.js trên phần cứng vật lý
  • Bun v1.2 official benchmarks (tháng 2 năm 2025) — HTTP/2 và Postgres client vs Node.js 22.13
  • Go vs Bun vs Node.js concurrent load benchmark — bài test 100k concurrent request (dev.to/hamzakhan, 2024)
  • Stack Overflow Developer Survey 2025 — số liệu sử dụng chuyên nghiệp
  • GitHub Octoverse 2025 — dữ liệu tăng trưởng ngôn ngữ
  • JetBrains Go Ecosystem Report 2025 — mức độ adoption Go, framework sử dụng, dữ liệu IDE

Hiệu năng

Bức tranh thực về throughput tại TechEmpower Round 22 với Fiber (Go, dựa trên fasthttp) so với Express (Node.js):

TestFiber (Go)Express (Node.js)Factor
Plaintext11,987,976 RPS1,204,969 RPS~10×
JSON serialization2,363,294 RPS949,717 RPS~2.5×
Single DB query953,016 RPS441,543 RPS~2.2×
Multiple queries (20)54,002 RPS85,011 RPSNode.js wins
Data updates29,984 RPS54,887 RPSNode.js wins

Có hai điều đáng chú ý. Thứ nhất, khoảng cách ~10× ở plaintext là thực nhưng cũng là con số ít hữu ích nhất — không có service production nào chạy ở ngưỡng throughput plaintext. Thứ hai, Node.js đảo chiều ưu thế ở các bài test truy vấn nhiều lần và cập nhật. Đây không phải hiệu ứng ngôn ngữ — đó là hành vi của connection pool. DB round-trip chiếm ưu thế ở quy mô đó.

Thêm Bun vào bức tranh, từ một benchmark độc lập với 100k concurrent request:

RuntimeRPSMemory
Go~90,00055 MB
Bun~80,00060 MB
Node.js~45,000100 MB

Bun thu hẹp ~88% khoảng cách throughput giữa Go và Node.js. Trong các benchmark HTTP handler đơn giản, Bun đôi khi nhỉnh hơn Go (bài test hello-world của peterbe.com báo cáo Bun nhanh hơn một chút, dù tác giả gọi đó là “kịch bản không thực tế”). HTTP/2 server của Bun v1.2 chạy nhanh hơn 2× so với Node.js 22 trên H2 benchmark; Postgres client (Bun.sql) đọc nhiều hơn 50% rows/giây so với các Postgres client phổ biến trên Node.js, nhờ sử dụng binary wire protocol và native prepared statements.

Ý nghĩa thực tế: nếu bottleneck của bạn là độ trễ database — và đó là trường hợp của hầu hết CRUD service — Go và Bun nằm trong ngưỡng sai số đo lường. Ưu thế của Go trở nên rõ ràng và đo được khi bạn vượt qua ~50k RPS tải thực, hoặc khi CPU work trên mỗi request không nhỏ (mã hóa, hashing, biến đổi dữ liệu).

Bộ nhớ sử dụng

Ở 100k concurrent request, Go chạy ở 55 MB và Bun ở 60 MB. Node.js đạt 100 MB — gần gấp đôi cả hai.

Mô hình goroutine giải thích hành vi này của Go. Mỗi goroutine khởi đầu với ~2 KB stack (runtime Go tự động tăng khi cần). Chạy hàng trăm nghìn goroutine trong một process là hoàn toàn khả thi. Trong Go FAQ: “It is practical to create hundreds of thousands of goroutines in the same address space.”

Có một điểm tinh tế đáng lưu ý. Trong WebSocket benchmark với 1 triệu kết nối hầu hết nhàn rỗi, Node.js có thể tiêu thụ ít bộ nhớ hơn Go trên mỗi kết nối. Event loop duy nhất có overhead gần như bằng không khi kết nối đang nhàn rỗi. Goroutine nổi trội khi kết nối đang tích cực tính toán; event loop nổi trội khi kết nối hầu hết đang chờ.

Nhận định về bộ nhớ: Go và Bun tương đương nhau dưới tải tích cực. Node.js dùng gấp ~2× cho các workload request nặng. Với pattern nhiều kết nối nhàn rỗi (WebSocket server với hầu hết client ngồi chờ), hãy đo lường trước khi kết luận.

Kiểu dữ liệu an toàn

Đây là nơi so sánh trở nên thú vị, vì câu trả lời phụ thuộc vào “type safe” có nghĩa là gì với bạn.

Go dùng kiểu danh nghĩa với structural interface. type UserID stringstring không thể thay thế cho nhau — compiler từ chối phép gán. Bất kỳ kiểu nào implement io.Reader đều thỏa mãn interface mà không cần khai báo. Kiểu dữ liệu tồn tại thực sự lúc runtime; any mang thông tin kiểu qua reflection. Không có null safety ở cấp ngôn ngữ, nhưng Go thay thế nullable bằng zero value và explicit error return — loại bỏ một lớp lớn lỗi kiểu NPE.

TypeScript dùng structural typing ở khắp nơi. Hai object có cùng cấu trúc có thể gán cho nhau. Hệ thống kiểu biểu đạt phong phú hơn Go — conditional types, mapped types, template literal types, variance annotations, infer. TypeScript 5.7 bổ sung phát hiện biến chưa khởi tạo và tsc nhanh hơn 2.5× nhờ V8 compile cache. Nhưng có một điểm cần lưu ý: kiểu dữ liệu biến mất lúc runtime. Để validate input tại ranh giới hệ thống (HTTP request body, kết quả DB), bạn cần một runtime validator:

ToolBundle sizeUse case
Zod v4~12 KBComplex schemas, broad ecosystem
Valibot< 1 KBEdge functions, bundle-sensitive

Go không có khoảng trống này. Struct tags (json:"field") xử lý serialization an toàn mà không cần thư viện bên ngoài.

Nhận định: Go thắng về runtime type guarantee ngay từ đầu. TypeScript cần Zod hoặc Valibot tại ranh giới hệ thống để đạt mức tương đương — đó là thông lệ chuẩn trong các dự án TS trưởng thành, nhưng là phần cấu hình bạn phải tự làm. Đối với code path nội bộ, type algebra phong phú hơn của TypeScript (conditional types, mapped types) biểu đạt các ràng buộc mà generics của Go chưa theo kịp.

Hệ sinh thái

Với nhu cầu cụ thể của một backend service, cả hai hệ sinh thái đều đáp ứng đủ. Sự khác biệt nằm ở chiều rộng so với chiều sâu.

Go HTTP framework (JetBrains Go Ecosystem Report 2025):

  • Gin — 48% developer Go; phổ biến nhất, middleware story trưởng thành
  • chi — 12%; router tương thích stdlib, không ma thuật
  • Echo — 16%; request binding gọn gàng
  • Fiber — 11%; throughput thuần cao nhất (fasthttp), đang tăng nhanh

TypeScript HTTP framework:

  • NestJS — enterprise-grade, DI kiểu Angular; lựa chọn hàng đầu cho team lớn cần cấu trúc
  • Hono — siêu nhẹ; chạy trên Node, Bun, Deno, Cloudflare Workers không cần thay đổi
  • Elysia — native Bun; nhanh, có end-to-end TypeScript inference
  • Express — vẫn là mặc định trong tài liệu hướng dẫn; 1.2M lượt tải tuần; 30 năm đã được kiểm chứng trong production

ORM / query layer:

Go đang thiên về code generation. sqlc biên dịch SQL query thành Go struct thuần túy mà không cần runtime reflection — đây là lựa chọn rút ngắn khoảng cách type-safety chặt nhất. Ent sinh code theo mô hình đồ thị cho schema phức tạp. GORM phổ biến nhất nhưng dựa trên reflection. Để có hiệu năng Postgres tối đa, pgx bỏ qua ORM hoàn toàn.

Tin tức TypeScript ORM năm 2025: Prisma 7 thay engine query Rust bằng TypeScript thuần, loại bỏ bước phân phối binary và giảm đáng kể cold-start cũng như kích thước bundle (ghi chú phát hành Prisma 7: “~90% bundle size nhỏ hơn, truy vấn nhanh hơn tới 3×”). Drizzle (SQL-first, không có query engine binary) là lựa chọn tốt hơn cho serverless. TypeORM đang già cỗi.

gRPC: grpc-go của Go là implementation tham chiếu, được duy trì bởi team gRPC tại Google. @grpc/grpc-js của TypeScript là bản port pure-JS — ổn định, với 2,998+ npm dependent, nhưng không phải implementation chính.

Lợi thế stdlib: Thư viện chuẩn của Go bao phủ HTTP server, TLS, JSON và cryptography ở chất lượng production. Một Go service cần ít package bên thứ ba hơn so với TypeScript service tương đương. npm của TypeScript có danh mục rộng hơn nhiều, nhưng Go stdlib nghĩa là bề mặt dependency của bạn nhỏ hơn theo mặc định.

Tuyển dụng và onboarding

Stack Overflow Developer Survey 2025, mức độ sử dụng chuyên nghiệp:

LanguageProfessional usageYoY growth
TypeScript48.8%+2.5%
Go17.4%+2.0%

GitHub Octoverse 2025 đặt TypeScript là ngôn ngữ #1 trên GitHub vào tháng 8 năm 2025 với 2.6 triệu người đóng góp hàng tháng và tăng trưởng +66.6% so với năm trước. Go nằm trong top 10 nhưng không có con số nổi bật.

Go có 2.2 triệu developer chuyên nghiệp sử dụng làm ngôn ngữ chính (JetBrains 2025) và hơn 5 triệu tổng cộng. Lương trung bình tại Mỹ là $135,000/năm, senior ở mức $160k–$180k — cao hơn 15–20% so với developer Node.js/TypeScript. Số job posting tăng 17% so với năm trước. Điểm trừ: “không có đủ developer giỏi để đáp ứng nhu cầu.” Khoảng trống nhân tài Go là rủi ro vận hành thực tế, không phải lý thuyết.

Developer TypeScript có nền tảng JavaScript có thể làm việc hiệu quả trong vài tuần. Go đòi hỏi học xử lý lỗi tường minh, mô hình goroutine và triết lý quản lý bộ nhớ — tính 1–3 tháng để đạt mức thoải mái ở môi trường production.

Nhận định về tuyển dụng: TypeScript có lợi thế ~3:1 về pool developer có sẵn. Nếu tốc độ mở rộng team là ràng buộc, đó là đòn bẩy thực sự. Go trả lương cao hơn và thu hút kỹ sư giỏi — nhưng bạn có thể phải chờ lâu hơn để lấp đầy vị trí và có thể cần đào tạo kỹ sư Go từ nền tảng TypeScript thay vì tuyển thẳng người có kinh nghiệm.

Mô hình xử lý đồng thời

Đây là nơi quyết định kiến trúc thực sự được đưa ra.

Mô hình của Go: M:N threading. Nhiều goroutine được multiplexed qua OS thread bởi Go scheduler (work-stealing, nhận biết GOMAXPROCS). Mỗi goroutine bắt đầu ở ~2 KB. Hàng trăm nghìn goroutine trong một process là khả thi. Go 1.23 cải thiện time.Timertime.Ticker cho các service có số goroutine lớn. Điểm yếu: CGO call chặn một OS thread; goroutine leak là có thật và cần pprof để tìm.

Mô hình của TypeScript: Event loop đơn luồng với cooperative async/await. Worker thread tồn tại cho CPU parallelism nhưng overhead phối hợp cao hơn goroutine. Điểm yếu đã được biết rõ: một CPU spike 100 ms chặn tất cả request đồng thời trên event loop đó. Với I/O-bound service — database call, external API call, object storage — event loop xử lý hiệu quả hàng nghìn kết nối đồng thời mà không tốn overhead của goroutine scheduler.

Bun mở rộng mô hình event loop với JavaScriptCore thay vì V8, HTTP/2 gốc (không cần thư viện thêm) và binary Postgres protocol của Bun.sql. Ngưỡng xử lý đồng thời vẫn là event loop, nhưng Bun đẩy ngưỡng đó cao hơn Node.js đáng kể.

Chọn Go khi: bạn cần xử lý CPU song song trên mỗi request (image processing, crypto, biến đổi dữ liệu), hoặc bạn vận hành service mà goroutine lập lịch độc lập qua nhiều core là quan trọng (background job runner, data pipeline có độ đồng thời cao).

Chọn TypeScript (Bun) khi: gần như toàn bộ thời gian chờ DB/network, bạn muốn hệ sinh thái npm, hoặc CPU-bound parallelism đủ hiếm để worker thread là đủ.

Chọn TypeScript (Node.js) khi: độ trưởng thành của Bun là rủi ro với use case cụ thể của bạn (native module ít phổ biến, yêu cầu hợp đồng LTS nghiêm ngặt) và hiệu năng không phải ưu tiên hàng đầu.

Kết luận

AxisGoTypeScript + BunTypeScript + Node.js
Raw throughput (simple HTTP)HighestWithin 10–15% of Go~50% of Go
Memory under load55 MB / 100k req60 MB / 100k req100 MB / 100k req
CPU-parallel concurrencyGoroutines — scales to 100k+Event loop — breaks on CPU workSame as Bun
Runtime type safetyStrong (structs + reflect)Requires Zod/ValibotSame as Bun
EcosystemDeep stdlib + curated packagesnpm breadth + Bun-native libsnpm breadth
Developer pool17.4% professional usage48.8% combined48.8% combined
Hiring cost (US)$135k avg, 15–20% premium, talent gap$105k–$125k, large poolSame as Bun
gRPCReference implementationSolid port, not referenceSame as Bun
DeploySingle static binaryNode/Bun runtime requiredRuntime required
Onboarding new engineers1–3 months to fluencyWeeks for JS devsSame as Bun

Chọn Go nếu: service cần duy trì >50k RPS tải ứng dụng thực, workload bao gồm CPU work đáng kể trên mỗi request, hoặc sự đơn giản trong vận hành với một binary deploy duy nhất là quan trọng với bạn.

Chọn TypeScript + Bun nếu: team đã có TypeScript expertise, service thiên về I/O (DB + API call chiếm ưu thế), bạn cần tuyển dụng nhanh từ pool lớn, hoặc đang chia sẻ type và business logic với frontend.

Chọn TypeScript + Node.js nếu: bạn cần hợp đồng LTS nghiêm ngặt, dependency bao gồm C++ native addon chưa chạy được trên Bun, hoặc độ sâu kiểm chứng trong production quan trọng hơn hiệu năng với mô hình rủi ro của bạn.

Ghi chú về tooling

Cả Go và TypeScript đều có editor support hạng nhất qua LSP. Nếu bạn đang chọn một IDE xử lý được cả hai mà không cần cấu hình, Cursor chạy gopls cho Go và tsserver cho TypeScript ngay từ đầu — hữu ích nếu team bạn làm việc với cả hai cùng lúc.

Lưu ý

  • Affiliate slug cho Railway và Fly.io chưa có trong toolchew. Cả hai nền tảng đều hỗ trợ Go single-binary và Bun gốc, và sẽ là những đề cập tự nhiên trong phần triển khai. Đã đăng ký để thêm vào mmo.affiliate_links.
  • TechEmpower Round 22 từ tháng 11 năm 2023. Round 25 (Q1 2026) được báo cáo có Bun với ~1M plaintext RPS/core (~2.5× Express, ~0.33× Go Gin). Khi dữ liệu Round 25 được xác nhận công khai, phần hiệu năng cần cập nhật với số liệu mới hơn.
  • Benchmark 100k concurrent request (dev.to/hamzakhan) là benchmark do một tác giả thực hiện trên phần cứng cụ thể. Coi các con số RPS tuyệt đối là định hướng, không phải đã được xác minh trong production. Thứ tự tương đối (Go > Bun > Node.js) nhất quán với nhiều nguồn độc lập.
  • Dữ liệu lương và thị trường việc làm Go lấy từ phân tích thị trường việc làm Go 2025 của Signify Technology — dataset của một recruiter đơn lẻ. Đối chiếu với dữ liệu lương của Stack Overflow trước khi dùng cho quyết định đãi ngộ.
  • Khả năng tương thích của Bun với native addon Node.js rộng nhưng chưa đạt 100%. Nếu stack của bạn bao gồm C++ addon, hãy kiểm tra trước khi cam kết với Bun.

Tài liệu tham khảo