Lanzamiento de Bun 1.2 - Mejoras en compatibilidad con Node.js y optimización del rendimiento

2025.12.02

Bun es un runtime de JavaScript ultrarrápido y gestor de paquetes escrito en el lenguaje Zig. Con Bun 1.2, la compatibilidad con Node.js ha mejorado significativamente, acelerando aún más su adopción empresarial.

Principales novedades de Bun 1.2

Resumen

flowchart TB
    subgraph Bun12["Bun 1.2"]
        subgraph Compat["Compatibilidad con Node.js"]
            C1["Soporte completo para node:cluster"]
            C2["Soporte para node:dgram (UDP)"]
            C3["Soporte parcial para node:v8"]
            C4["Más del 90% de paquetes npm funcionan"]
        end

        subgraph Features["Nuevas funciones"]
            F1["Cliente S3 integrado"]
            F2["API Bun.color() para procesamiento de colores"]
            F3["Watch Mode mejorado"]
            F4["Bundler HTML/CSS"]
        end

        subgraph Perf["Rendimiento"]
            P1["Servidor HTTP: 30% más rápido"]
            P2["Uso de memoria: 20% menos"]
            P3["Instalación de paquetes: 2x más rápida"]
        end
    end

Mejoras en compatibilidad con Node.js

Soporte para node:cluster

// cluster-server.ts - Servidor multiproceso
import cluster from 'node:cluster';
import { cpus } from 'node:os';
import { serve } from 'bun';

const numCPUs = cpus().length;

if (cluster.isPrimary) {
  console.log(`Primary ${process.pid} is running`);
  console.log(`Forking ${numCPUs} workers...`);

  // Fork de workers según el número de núcleos de CPU
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died`);
    // Reinicio automático
    cluster.fork();
  });

  // Recepción de mensajes de los workers
  cluster.on('message', (worker, message) => {
    console.log(`Message from worker ${worker.process.pid}:`, message);
  });
} else {
  // Proceso worker
  const server = serve({
    port: 3000,
    fetch(req) {
      return new Response(`Hello from worker ${process.pid}`);
    },
  });

  console.log(`Worker ${process.pid} started on port ${server.port}`);

  // Enviar mensaje al primario
  process.send?.({ status: 'ready', pid: process.pid });
}

Soporte para node:dgram (UDP)

// udp-server.ts
import dgram from 'node:dgram';

const server = dgram.createSocket('udp4');

server.on('error', (err) => {
  console.error(`Server error:\n${err.stack}`);
  server.close();
});

server.on('message', (msg, rinfo) => {
  console.log(`Server got: ${msg} from ${rinfo.address}:${rinfo.port}`);

  // Devolver respuesta
  const response = Buffer.from(`Received: ${msg}`);
  server.send(response, rinfo.port, rinfo.address);
});

server.on('listening', () => {
  const address = server.address();
  console.log(`UDP server listening on ${address.address}:${address.port}`);
});

server.bind(41234);

// udp-client.ts
const client = dgram.createSocket('udp4');
const message = Buffer.from('Hello UDP Server');

client.send(message, 41234, 'localhost', (err) => {
  if (err) {
    console.error('Send error:', err);
    client.close();
    return;
  }
  console.log('Message sent');
});

client.on('message', (msg) => {
  console.log(`Received: ${msg}`);
  client.close();
});

Cliente S3 integrado

Simplificación de operaciones S3

// Bun.s3 - Cliente S3 nativo

// Obtención automática de credenciales desde variables de entorno
// AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION

// Subida de archivos
const file = Bun.file('./large-file.zip');
await Bun.s3.write('my-bucket/uploads/large-file.zip', file);

// Subida en streaming
const response = await fetch('https://example.com/large-video.mp4');
await Bun.s3.write('my-bucket/videos/video.mp4', response);

// Escritura de datos de texto
await Bun.s3.write(
  'my-bucket/data/config.json',
  JSON.stringify({ setting: 'value' }),
  { contentType: 'application/json' }
);

// Lectura de archivos
const data = await Bun.s3.file('my-bucket/data/config.json').text();
const config = JSON.parse(data);

// Lectura como ArrayBuffer
const buffer = await Bun.s3.file('my-bucket/images/photo.jpg').arrayBuffer();

// Lectura en streaming
const stream = Bun.s3.file('my-bucket/large-data.csv').stream();

// Obtención de información del archivo
const s3File = Bun.s3.file('my-bucket/document.pdf');
console.log({
  exists: await s3File.exists(),
  size: await s3File.size,
  lastModified: await s3File.lastModified,
});

// Eliminación de archivos
await Bun.s3.delete('my-bucket/temp/old-file.txt');

// Generación de URL firmada
const signedUrl = await Bun.s3.presign('my-bucket/private/file.pdf', {
  expiresIn: 3600, // 1 hora
  method: 'GET',
});

// Obtención de lista
for await (const object of Bun.s3.list('my-bucket/uploads/')) {
  console.log(object.key, object.size, object.lastModified);
}

Servidor de archivos usando S3

// s3-file-server.ts
import { serve } from 'bun';

serve({
  port: 3000,

  async fetch(req) {
    const url = new URL(req.url);
    const path = url.pathname.slice(1); // Eliminar / inicial

    if (req.method === 'GET') {
      // Streaming directo desde S3
      const s3File = Bun.s3.file(`my-bucket/${path}`);

      if (!(await s3File.exists())) {
        return new Response('Not Found', { status: 404 });
      }

      return new Response(s3File.stream(), {
        headers: {
          'Content-Type': s3File.type || 'application/octet-stream',
          'Content-Length': String(await s3File.size),
        },
      });
    }

    if (req.method === 'PUT') {
      // Streaming del cuerpo de la petición a S3
      await Bun.s3.write(`my-bucket/${path}`, req);
      return new Response('Uploaded', { status: 201 });
    }

    if (req.method === 'DELETE') {
      await Bun.s3.delete(`my-bucket/${path}`);
      return new Response('Deleted', { status: 200 });
    }

    return new Response('Method Not Allowed', { status: 405 });
  },
});

API Bun.color()

Nueva API para procesamiento de colores

// Bun.color() - Procesamiento de colores de alto rendimiento

// Análisis de cadenas de color CSS
const red = Bun.color('red');
console.log(red); // { r: 255, g: 0, b: 0, a: 1 }

// Conversión desde HEX
const hex = Bun.color('#3498db');
console.log(hex); // { r: 52, g: 152, b: 219, a: 1 }

// Conversión desde RGB
const rgb = Bun.color('rgb(100, 150, 200)');
console.log(rgb); // { r: 100, g: 150, b: 200, a: 1 }

// Conversión desde HSL
const hsl = Bun.color('hsl(210, 60%, 50%)');
console.log(hsl); // { r: ..., g: ..., b: ..., a: 1 }

// Salida en formato array
const [r, g, b, a] = Bun.color('#ff6b6b', 'array');
console.log(r, g, b, a); // 255, 107, 107, 1

// Conversión a cadena HEX
const hexString = Bun.color({ r: 255, g: 100, b: 50, a: 1 }, 'hex');
console.log(hexString); // '#ff6432'

// Conversión a formato CSS
const cssRgb = Bun.color({ r: 255, g: 100, b: 50, a: 0.5 }, 'css');
console.log(cssRgb); // 'rgba(255, 100, 50, 0.5)'

// Operaciones con colores
function lighten(color: string, amount: number): string {
  const { r, g, b, a } = Bun.color(color)!;
  return Bun.color({
    r: Math.min(255, r + amount),
    g: Math.min(255, g + amount),
    b: Math.min(255, b + amount),
    a,
  }, 'hex');
}

function darken(color: string, amount: number): string {
  const { r, g, b, a } = Bun.color(color)!;
  return Bun.color({
    r: Math.max(0, r - amount),
    g: Math.max(0, g - amount),
    b: Math.max(0, b - amount),
    a,
  }, 'hex');
}

console.log(lighten('#3498db', 30)); // Más claro
console.log(darken('#3498db', 30));  // Más oscuro

Watch Mode mejorado

Mejoras en la vigilancia de archivos

// Servidor de desarrollo con bun --watch

// package.json
{
  "scripts": {
    "dev": "bun --watch src/index.ts",
    "dev:hot": "bun --hot src/server.ts"
  }
}

// --watch: Reinicio del proceso
// --hot: Hot reload (mantiene el estado)
// hot-reload-server.ts
import { serve } from 'bun';

// Estado global (se mantiene durante hot reload)
declare global {
  var requestCount: number;
}
globalThis.requestCount ??= 0;

serve({
  port: 3000,

  fetch(req) {
    globalThis.requestCount++;

    return new Response(`
      <html>
        <body>
          <h1>Hot Reload Demo</h1>
          <p>Request count: ${globalThis.requestCount}</p>
          <p>Last updated: ${new Date().toISOString()}</p>
        </body>
      </html>
    `, {
      headers: { 'Content-Type': 'text/html' },
    });
  },
});

console.log('Server started on port 3000');

Vigilancia de archivos programática

// Bun.watch() - API de vigilancia de archivos
const watcher = Bun.watch({
  paths: ['./src'],
  recursive: true,
  filter: (path) => path.endsWith('.ts') || path.endsWith('.tsx'),
});

for await (const event of watcher) {
  console.log(`${event.type}: ${event.path}`);

  if (event.type === 'change' || event.type === 'create') {
    // Procesamiento al cambiar archivos
    await runTests(event.path);
  }

  if (event.type === 'delete') {
    // Procesamiento al eliminar archivos
    console.log(`File deleted: ${event.path}`);
  }
}

async function runTests(changedFile: string) {
  const testFile = changedFile.replace('.ts', '.test.ts');
  if (await Bun.file(testFile).exists()) {
    const proc = Bun.spawn(['bun', 'test', testFile]);
    await proc.exited;
  }
}

Bundler HTML

Simplificación del build de frontend

// bun build --html

// Entrada: index.html
// <!DOCTYPE html>
// <html>
// <head>
//   <link rel="stylesheet" href="./styles.css">
// </head>
// <body>
//   <div id="app"></div>
//   <script type="module" src="./app.tsx"></script>
// </body>
// </html>

// Comando de build
// bun build ./index.html --outdir=./dist

// Resultado:
// - Detección automática de CSS/JS en HTML
// - Compilación automática de TypeScript/TSX
// - Bundling y optimización de CSS
// - Resolución de dependencias
// Build HTML programático
const result = await Bun.build({
  entrypoints: ['./src/index.html'],
  outdir: './dist',
  minify: true,
  sourcemap: 'external',
  splitting: true,
  target: 'browser',
  define: {
    'process.env.NODE_ENV': '"production"',
  },
  loader: {
    '.png': 'file',
    '.svg': 'file',
    '.woff2': 'file',
  },
});

if (!result.success) {
  console.error('Build failed:');
  for (const log of result.logs) {
    console.error(log);
  }
  process.exit(1);
}

console.log('Build outputs:');
for (const output of result.outputs) {
  console.log(`  ${output.path} (${output.size} bytes)`);
}

Mejoras de rendimiento

Comparación de benchmarks

Rendimiento del servidor HTTP (req/seg)

RuntimeHello WorldJSON APIServicio de archivos
Bun 1.2250,000180,000150,000
Bun 1.1190,000140,000120,000
Node.js 2075,00055,00045,000
Deno 1.4095,00070,00060,000

Tiempo de instalación de paquetes (node_modules)

HerramientaInstalación limpiaCon caché
bun install2.1s0.3s
npm install15.2s8.5s
yarn install12.8s4.2s
pnpm install8.5s1.8s

Ejemplo de uso de API optimizado

// Servidor JSON de alto rendimiento
import { serve } from 'bun';

const users = new Map<string, User>();

serve({
  port: 3000,

  async fetch(req) {
    const url = new URL(req.url);

    // Bun.router() - Routing de alto rendimiento (función futura)
    if (url.pathname.startsWith('/api/users')) {
      const userId = url.pathname.split('/')[3];

      if (req.method === 'GET') {
        if (userId) {
          const user = users.get(userId);
          if (!user) {
            return Response.json({ error: 'Not found' }, { status: 404 });
          }
          return Response.json(user);
        }
        return Response.json([...users.values()]);
      }

      if (req.method === 'POST') {
        const body = await req.json();
        const id = crypto.randomUUID();
        const user = { id, ...body, createdAt: new Date().toISOString() };
        users.set(id, user);
        return Response.json(user, { status: 201 });
      }
    }

    return new Response('Not Found', { status: 404 });
  },
});

Funciones nativas de Bun

Bun.sql (Operaciones SQLite de alto rendimiento)

// Bun.sql - Driver SQLite integrado

import { Database } from 'bun:sqlite';

const db = new Database(':memory:');

// Creación de tabla
db.run(`
  CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
  )
`);

// Sentencias preparadas
const insertUser = db.prepare(`
  INSERT INTO users (name, email) VALUES ($name, $email)
`);

const getUser = db.prepare(`
  SELECT * FROM users WHERE id = $id
`);

const getAllUsers = db.prepare(`
  SELECT * FROM users ORDER BY created_at DESC
`);

// Inserción de datos
insertUser.run({ $name: 'Alice', $email: 'alice@example.com' });
insertUser.run({ $name: 'Bob', $email: 'bob@example.com' });

// Obtención de datos
const user = getUser.get({ $id: 1 });
console.log(user); // { id: 1, name: 'Alice', ... }

const users = getAllUsers.all();
console.log(users);

// Transacciones
const insertMany = db.transaction((users: Array<{ name: string; email: string }>) => {
  for (const user of users) {
    insertUser.run({ $name: user.name, $email: user.email });
  }
});

insertMany([
  { name: 'Charlie', email: 'charlie@example.com' },
  { name: 'Diana', email: 'diana@example.com' },
]);

Bun.password (Hash de contraseñas)

// Bun.password - Hash seguro de contraseñas

// Hashear contraseña
const hash = await Bun.password.hash('my-secure-password', {
  algorithm: 'argon2id', // bcrypt, argon2id, argon2i, argon2d
  memoryCost: 65536,     // 64MB
  timeCost: 3,
});

console.log(hash);
// $argon2id$v=19$m=65536,t=3,p=1$...

// Verificar contraseña
const isValid = await Bun.password.verify(
  'my-secure-password',
  hash
);
console.log(isValid); // true

// Uso de bcrypt
const bcryptHash = await Bun.password.hash('password123', {
  algorithm: 'bcrypt',
  cost: 12,
});

const bcryptValid = await Bun.password.verify('password123', bcryptHash);

Bun.sleep y temporizadores

// Bun.sleep - Sleep de alta precisión

// Especificación en milisegundos
await Bun.sleep(1000); // Esperar 1 segundo

// Temporizador con nombre (cancelable)
const timer = Bun.sleep(5000);
setTimeout(() => timer.cancel(), 2000); // Cancelar después de 2 segundos

try {
  await timer;
} catch (e) {
  console.log('Timer was cancelled');
}

// sleepSync (versión síncrona)
Bun.sleepSync(100); // Espera síncrona de 100ms

Guía de migración

Migración desde Node.js

// package.json
{
  "scripts": {
    // Node.js
    "dev:node": "node --watch src/index.js",
    "build:node": "tsc && node dist/index.js",

    // Bun (ejecución directa de TypeScript)
    "dev": "bun --watch src/index.ts",
    "build": "bun build src/index.ts --outdir=dist",
    "start": "bun dist/index.js"
  }
}
// Verificación de compatibilidad
// bun pm untrusted - Verificar paquetes no confiables
// bun pm verify    - Verificar integridad de paquetes

// Problemas comunes de compatibilidad y soluciones:

// 1. __dirname / __filename
// Node.js: disponible globalmente
// Bun: usar import.meta en ESM
const __dirname = import.meta.dir;
const __filename = import.meta.file;

// 2. require() en ESM
// En Bun usar import.meta.require()
const pkg = import.meta.require('./package.json');

// 3. Native addons
// Algunos módulos nativos son incompatibles
// Alternativa: API nativa de Bun o WASM

Ejemplo de migración Express a Elysia

// Express (Node.js)
import express from 'express';
const app = express();

app.get('/users/:id', (req, res) => {
  const { id } = req.params;
  res.json({ id, name: 'User' });
});

app.listen(3000);

// Elysia (Framework optimizado para Bun)
import { Elysia } from 'elysia';

const app = new Elysia()
  .get('/users/:id', ({ params: { id } }) => ({
    id,
    name: 'User',
  }))
  .listen(3000);

console.log(`Server running at ${app.server?.hostname}:${app.server?.port}`);

Resumen

Bun 1.2 ha alcanzado un nivel práctico como alternativa a Node.js.

Fortalezas de Bun 1.2

CaracterísticaBeneficio
Inicio ultrarrápidoAcelera el ciclo de desarrollo
Ejecución directa de TypeScriptSin paso de build
Todo en unoRuntime + Bundler + PM
Compatibilidad con Node.jsReutilización de código existente

Criterios de adopción

  • Nuevos proyectos: Se puede adoptar activamente
  • Proyectos Node.js existentes: Migrar después de pruebas de compatibilidad
  • Enterprise: Se recomienda adopción gradual

Bun se está convirtiendo en el nuevo estándar del desarrollo JavaScript/TypeScript.

Enlaces de referencia

← Volver a la lista