Bun y Zig: cómo el runtime de JavaScript más rápido usa Zig en su núcleo

Bun es el runtime de JavaScript más rápido del mercado. En benchmarks de operaciones de E/S, servidor HTTP y arranque de procesos supera a Node.js y Deno por márgenes amplios. Detrás de esos números hay una decisión de diseño que muchos desarrolladores JavaScript desconocen: Bun está escrito en Zig, no en C ni en C++. Jarred Sumner, su creador, eligió Zig en 2021 cuando el lenguaje todavía estaba en versiones muy tempranas.

La arquitectura de Bun

Bun tiene tres capas principales. El motor JavaScript es JavaScriptCore (JSC), el motor de Apple usado en Safari, que en benchmarks de ejecución pura de JavaScript es competitivo o superior a V8 (el de Node.js y Deno). El runtime que rodea al motor, las APIs de Node.js, el sistema de ficheros, las conexiones de red y el servidor HTTP están escritos en Zig. Y el transpilador de TypeScript y JSX está también implementado en Zig, lo que explica en parte la velocidad de transpilación.

Por qué Zig para un runtime de JavaScript

Sumner eligió Zig por tres razones que él mismo ha explicado públicamente. La primera es el interop con C: JavaScriptCore es una biblioteca C/C++ y Zig puede incluir sus cabeceras directamente con @cImport sin ninguna capa de bindings. En Node.js, el puente entre V8 (C++) y el runtime está mediado por N-API, que añade overhead. En Bun, la integración con JSC es directa.

La segunda es el control de la memoria. En un runtime de JavaScript, el GC del motor ya gestiona los objetos JavaScript, pero todo lo demás (buffers de red, ficheros, strings internos, estructuras del runtime) puede gestionarse manualmente. Con Zig, Sumner puede decidir exactamente cómo se organiza la memoria para cada tipo de dato, lo que reduce la presión sobre el GC de JSC y mejora la localidad de caché.

La tercera es la velocidad de compilación y la facilidad de cross-compilation. Bun distribuye binarios para Linux x86_64, Linux ARM64, macOS x86_64 y macOS ARM64. Con Zig, la pipeline de cross-compilation es sencilla.

Comparación de rendimiento

Benchmark

Node.js 22

Deno 2

Bun 1.x

Arranque (ms)

~80ms

~30ms

~5ms

Servidor HTTP (req/s)

~70k

~80k

~120k

Lectura de ficheros

base

similar

2-3x más rápido

SQLite (ops/s)

via better-sqlite3

via FFI

nativo, más rápido

Los números exactos dependen del benchmark específico y de la versión, pero el patrón general es consistente: Bun es significativamente más rápido en operaciones de E/S y en arranque, y competitivo en ejecución pura de JavaScript.

Lo que Bun ofrece además del runtime

Bun no solo reemplaza Node.js como runtime. También incluye:

  • Gestor de paquetes: bun install es 10-25x más rápido que npm install. Usa un formato de lockfile binario propio y caché agresiva.
  • Transpilador nativo: TypeScript y JSX se transpilan sin tsc ni Babel. Escrito en Zig, es mucho más rápido que las alternativas JS.
  • Bundler: bun build produce bundles de producción sin Webpack ni esbuild.
  • Test runner: bun test es compatible con la API de Jest pero más rápido.
  • SQLite nativo: bun:sqlite es una API nativa para SQLite sin dependencias externas.

Compatibilidad con Node.js

Bun implementa la mayoría de las APIs de Node.js y es compatible con npm. La mayoría de proyectos Node.js funcionan en Bun sin cambios. Las diferencias están en APIs muy específicas o en comportamientos edge case del event loop. Para proyectos nuevos, Bun es una opción directa. Para proyectos existentes, la migración suele ser sencilla.

# Instalar Bun
curl -fsSL https://bun.sh/install | bash

# Instalar dependencias de un proyecto Node.js existente
bun install

# Ejecutar un script
bun run index.ts  # TypeScript directamente, sin transpilación previa

# Servidor HTTP mínimo en Bun
bun --eval "Bun.serve({ fetch(req) { return new Response('hola'); }, port: 3000 })"

Zig en producción: la lección de Bun y TigerBeetle

Bun y TigerBeetle son los dos proyectos más importantes escritos en Zig que están en producción real. Los dos eligieron Zig por razones similares: interop directo con C sin overhead, control total de la memoria y ausencia de runtime oculto. Los dos son proyectos donde el rendimiento no es un nice-to-have sino una característica central del producto.

Esto dice algo sobre dónde encaja Zig mejor: no es para cualquier proyecto, pero para los proyectos donde el rendimiento de bajo nivel importa, tiene ventajas reales sobre las alternativas. Si quieres ver cómo Bun gestiona la interop con JavaScriptCore (que es una biblioteca C), el artículo sobre interop Zig-C explica el mecanismo que hace posible esa integración. Y para entender el contexto completo del lenguaje, el artículo de introducción a Zig con el que empieza esta serie es el punto de partida. También puedes leer más sobre Bun en el artículo específico sobre Bun 1.3.

Imagen: Pexels / Robin Schreiner

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP