Bun 1.2: El Runtime JavaScript Que Está Rompiendo Récords de Performance
Hola HaWkers, si acompañas el ecosistema JavaScript, probablemente ya oíste hablar de Bun. Este runtime relativamente nuevo está conquistando desarrolladores con números de performance impresionantes.
¿Ya te frustraste esperando que npm install termine? ¿O tal vez sentiste que tu servidor Node.js podría ser más rápido? Bun promete resolver esos problemas y mucho más.
Qué Es Bun
Bun es un runtime JavaScript y toolkit todo-en-uno que incluye:
Componentes Principales:
- Runtime JavaScript (alternativa a Node.js)
- Package manager (alternativa a npm/yarn/pnpm)
- Bundler (alternativa a webpack/esbuild)
- Test runner (alternativa a Jest/Vitest)
- TypeScript transpiler nativo
¿El diferencial? Todo esto fue escrito en Zig y C++ para máxima performance, usando JavaScriptCore (motor de Safari) en vez de V8.
Novedades de Bun 1.2
Windows Nativo
Finalmente, soporte completo a Windows:
# Instalación en Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"
# O vía npm
npm install -g bun
# Verificar instalación
bun --version
# 1.2.0Antes de la versión 1.2, Bun en Windows dependía de WSL. Ahora funciona nativamente.
S3 Object Storage Nativo
Bun 1.2 introdujo APIs nativas para Amazon S3:
// Acceso nativo a S3 - sin SDKs pesadas
import { S3Client } from "bun";
const s3 = new S3Client({
accessKeyId: Bun.env.AWS_ACCESS_KEY_ID,
secretAccessKey: Bun.env.AWS_SECRET_ACCESS_KEY,
region: "us-east-1"
});
// Upload de archivo
const file = Bun.file("./image.png");
await s3.write("my-bucket/image.png", file);
// Download
const downloaded = await s3.file("my-bucket/image.png");
await Bun.write("./downloaded.png", downloaded);
// Streaming de archivos grandes
const stream = s3.file("my-bucket/large-video.mp4").stream();Postgres Nativo
Driver PostgreSQL integrado al runtime:
// Sin instalar pg o postgres.js
import { SQL } from "bun";
const sql = new SQL({
hostname: "localhost",
database: "myapp",
username: "user",
password: "password"
});
// Queries con tagged templates
const users = await sql`SELECT * FROM users WHERE active = true`;
// Queries parametrizadas (seguras contra SQL injection)
const userId = 123;
const user = await sql`SELECT * FROM users WHERE id = ${userId}`;
// Transacciones
await sql.begin(async (tx) => {
await tx`UPDATE accounts SET balance = balance - 100 WHERE id = 1`;
await tx`UPDATE accounts SET balance = balance + 100 WHERE id = 2`;
});
Performance Comparada
Package Manager
Vamos a comparar instalación de dependencias:
# Proyecto con ~50 dependencias
# npm
time npm install
# real: 45.2s
# yarn
time yarn install
# real: 32.1s
# pnpm
time pnpm install
# real: 18.7s
# bun
time bun install
# real: 2.3sBun es consistentemente 10-20x más rápido que npm.
Runtime Performance
Servidor HTTP:
// Bun native server
Bun.serve({
port: 3000,
fetch(req) {
return new Response("Hello World");
}
});
// Resultados: ~185,000 req/sComparativo de requisiciones por segundo:
| Runtime | Hello World | JSON API | File Serve |
|---|---|---|---|
| Bun 1.2 | 185,000 | 142,000 | 78,000 |
| Deno 2.0 | 125,000 | 95,000 | 45,000 |
| Node 22 | 118,000 | 88,000 | 52,000 |
Bundler
# Build de proyecto React grande (~500 componentes)
# webpack
time npx webpack build
# real: 28.4s
# esbuild
time npx esbuild src/index.tsx --bundle --outdir=dist
# real: 0.8s
# bun
time bun build src/index.tsx --outdir=dist
# real: 0.4s
Usando Bun en la Práctica
Creando un Proyecto
# Crear proyecto
mkdir mi-proyecto && cd mi-proyecto
bun init
# Estructura creada:
# mi-proyecto/
# .gitignore
# bun.lockb
# index.ts
# package.json
# README.md
# tsconfig.jsonServidor Web Completo
// server.ts
import { Hono } from "hono";
import { cors } from "hono/cors";
import { logger } from "hono/logger";
const app = new Hono();
// Middlewares
app.use("*", logger());
app.use("/api/*", cors());
// Database connection (nativo de Bun)
const db = new SQL({
hostname: Bun.env.DB_HOST,
database: Bun.env.DB_NAME,
username: Bun.env.DB_USER,
password: Bun.env.DB_PASSWORD
});
// Routes
app.get("/", (c) => c.text("Hello Bun!"));
app.get("/api/users", async (c) => {
const users = await db`SELECT id, name, email FROM users`;
return c.json(users);
});
app.post("/api/users", async (c) => {
const body = await c.req.json();
const { name, email } = body;
const [user] = await db`
INSERT INTO users (name, email)
VALUES (${name}, ${email})
RETURNING *
`;
return c.json(user, 201);
});
// File uploads (con S3 nativo)
app.post("/api/upload", async (c) => {
const form = await c.req.formData();
const file = form.get("file") as File;
const s3 = new S3Client({
accessKeyId: Bun.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: Bun.env.AWS_SECRET_ACCESS_KEY!,
region: "us-east-1"
});
const key = `uploads/${Date.now()}-${file.name}`;
await s3.write(`my-bucket/${key}`, file);
return c.json({ url: `https://my-bucket.s3.amazonaws.com/${key}` });
});
export default {
port: 3000,
fetch: app.fetch
};Ejecutar y Desarrollar
# Correr en desarrollo (con hot reload)
bun --watch run server.ts
# Correr en producción
bun run server.ts
# Scripts de package.json
bun run dev
bun run build
bun run test
Sistema de Tests
Bun tiene test runner integrado compatible con Jest:
// math.ts
export function add(a: number, b: number): number {
return a + b;
}
export function multiply(a: number, b: number): number {
return a * b;
}
export async function fetchUser(id: number) {
const response = await fetch(`https://api.example.com/users/${id}`);
return response.json();
}// math.test.ts
import { describe, test, expect, mock, beforeEach } from "bun:test";
import { add, multiply, fetchUser } from "./math";
describe("Math functions", () => {
test("add should sum two numbers", () => {
expect(add(2, 3)).toBe(5);
expect(add(-1, 1)).toBe(0);
});
test("multiply should multiply two numbers", () => {
expect(multiply(3, 4)).toBe(12);
expect(multiply(0, 100)).toBe(0);
});
});
describe("API functions", () => {
beforeEach(() => {
// Mock de fetch global
global.fetch = mock(async (url: string) => {
return new Response(JSON.stringify({
id: 1,
name: "Test User"
}));
});
});
test("fetchUser should return user data", async () => {
const user = await fetchUser(1);
expect(user.name).toBe("Test User");
});
});# Correr tests
bun test
# Con coverage
bun test --coverage
# Watch mode
bun test --watch
# Filtrar tests
bun test --filter "Math"
Bundler Integrado
// bun.config.ts (opcional)
export default {
entrypoints: ["./src/index.tsx"],
outdir: "./dist",
target: "browser",
minify: true,
sourcemap: "external",
splitting: true,
plugins: [
// Plugins customizados
]
};# Build simple
bun build ./src/index.tsx --outdir ./dist
# Build con minificación
bun build ./src/index.tsx --outdir ./dist --minify
# Build para Node.js
bun build ./src/server.ts --outdir ./dist --target node
# Watch mode
bun build ./src/index.tsx --outdir ./dist --watchMacros en Tiempo de Build
Una feature única de Bun son macros que corren en tiempo de compilación:
// config.ts
export const VERSION = await Bun.file("./version.txt").text();
export const BUILD_TIME = new Date().toISOString();
// ¡Esto es evaluado en tiempo de build, no en runtime!
export const ENV_CONFIG = {
apiUrl: Bun.env.API_URL,
debug: Bun.env.DEBUG === "true"
};// app.ts
import { VERSION, BUILD_TIME } from "./config" with { type: "macro" };
console.log(`Version: ${VERSION}`);
console.log(`Built at: ${BUILD_TIME}`);
// En el bundle final, esos valores son sustituidos por strings literales
Compatibilidad con Node.js
Bun es altamente compatible con Node.js:
// La mayoría del código Node.js funciona sin cambios
import express from "express";
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcrypt";
const app = express();
const prisma = new PrismaClient();
app.use(express.json());
app.post("/login", async (req, res) => {
const { email, password } = req.body;
const user = await prisma.user.findUnique({
where: { email }
});
if (!user) {
return res.status(401).json({ error: "User not found" });
}
const valid = await bcrypt.compare(password, user.password);
if (!valid) {
return res.status(401).json({ error: "Invalid password" });
}
res.json({ user: { id: user.id, email: user.email } });
});
// Funciona con bun run o node
app.listen(3000);APIs Node.js Soportadas
// Mayoría de las APIs Node.js funcionan
import fs from "fs";
import path from "path";
import crypto from "crypto";
import { Buffer } from "buffer";
import { EventEmitter } from "events";
import { Readable, Writable } from "stream";
// process global
console.log(process.env.NODE_ENV);
console.log(process.cwd());
// APIs Bun adicionales
const file = Bun.file("./data.json");
const content = await file.text();
const hash = Bun.hash("sha256", "data");
Cuándo Usar Bun
Casos Ideales
1. Proyectos Nuevos que Necesitan Performance:
// APIs de alta performance
// Procesamiento de datos en tiempo real
// Servidores de WebSocket
// Microservicios
Bun.serve({
port: 3000,
websocket: {
message(ws, message) {
// Broadcast para todos los clientes
server.publish("chat", message);
}
},
fetch(req, server) {
if (server.upgrade(req)) {
return; // Upgrade para WebSocket
}
return new Response("Hello!");
}
});2. Scripts y Herramientas CLI:
#!/usr/bin/env bun
// Script de migración de datos
import { SQL } from "bun";
const sourceDb = new SQL({ /* config fuente */ });
const targetDb = new SQL({ /* config destino */ });
console.log("Starting migration...");
const users = await sourceDb`SELECT * FROM users`;
for (const user of users) {
await targetDb`
INSERT INTO users (id, name, email)
VALUES (${user.id}, ${user.name}, ${user.email})
`;
console.log(`Migrated user ${user.id}`);
}
console.log(`Migration complete! ${users.length} users migrated.`);3. Cuando Tiempo de Build Importa:
# CI/CD más rápido
# bun install + bun build en segundos
# vs npm install + webpack en minutosCuándo Evitar (Por Ahora)
- Proyectos que dependen de native addons complejos
- Ecosistemas muy específicos de Node.js
- Cuando estabilidad es más importante que performance
- Equipos que no pueden absorber curva de aprendizaje
Migrando de Node.js
Paso 1: Instalar Bun
# Unix/Mac
curl -fsSL https://bun.sh/install | bash
# Windows
powershell -c "irm bun.sh/install.ps1 | iex"Paso 2: Convertir package.json
# Remover node_modules y lockfiles antiguos
rm -rf node_modules package-lock.json yarn.lock pnpm-lock.yaml
# Instalar con Bun
bun install
# Crea bun.lockbPaso 3: Testar Compatibilidad
# Correr tests
bun test
# Correr aplicación
bun run dev
# Verificar si todo funcionaPaso 4: Optimizar para Bun
// Sustituir paquetes por APIs nativas cuando posible
// Antes: pg o postgres.js
import { Client } from "pg";
// Después: SQL nativo de Bun
import { SQL } from "bun";
// Antes: aws-sdk para S3
import AWS from "aws-sdk";
// Después: S3 nativo de Bun
import { S3Client } from "bun";
Conclusión
Bun 1.2 representa un avance significativo en el ecosistema JavaScript. Con performance impresionante, APIs nativas para tareas comunes, y excelente compatibilidad con Node.js, se está tornando una opción cada vez más viable para proyectos serios.
La principal recomendación es: experimenta. Comienza con un proyecto nuevo o un script, y ve expandiendo conforme ganes confianza. El ecosistema Bun aún está madurando, pero la dirección es prometedora.
Si quieres comparar Bun con otras opciones de runtime, recomiendo que revises otro artículo: Deno 2.0 vs Node.js: La Batalla de los Runtimes donde vas a descubrir cómo cada runtime se posiciona en el mercado actual.

