Bun Runtime con Claude Code: guía práctica de adopción
Adopta Bun con Claude Code: Bun.serve, scripts de package, tests, compatibilidad Node y riesgos reales.
Bun no es solo un runtime rápido. En la práctica junta runtime, gestor de paquetes, ejecutor de scripts, test runner y bundler. Para principiantes: runtime es la capa que ejecuta JavaScript o TypeScript; un package script es un atajo dentro de package.json; un test runner busca y ejecuta pruebas.
Con Claude Code, la adopción segura no empieza reemplazando Node.js completo. Empieza con una prueba pequeña: ejecutar scripts con bun run, crear una API mínima con Bun.serve, correr bun test y revisar riesgos de compatibilidad Node antes de producción. Revisa la documentación de Bun, Bun.serve, bun run, Bun test runner y compatibilidad con Node.js.
También conviene leer la guía de desarrollo API, las estrategias de testing y la optimización de performance.
Define un alcance reversible
Pide primero una auditoría:
Revisa este repositorio para una adopción gradual de Bun. No modifiques archivos todavía. Lee
package.json, lockfiles, tests, CI, Docker y uso de APIs de Node. Devuelve una tabla con candidatos seguros, candidatos riesgosos y comandos de verificación.
| Paso | Qué probar | Señal de éxito |
|---|---|---|
| 1 | bun install en una rama | El diff de dependencias se entiende |
| 2 | bun run para scripts | Los scripts mantienen su significado |
| 3 | bun test en pruebas pequeñas | Las diferencias con Jest son visibles |
| 4 | Bun.serve para una API mínima | El comportamiento HTTP se puede probar |
Ejemplo copiable con Bun.serve
mkdir bun-claude-lab
cd bun-claude-lab
bun init -y
{
"name": "bun-claude-lab",
"type": "module",
"scripts": {
"dev": "bun --watch src/server.ts",
"start": "bun src/server.ts",
"test": "bun test",
"check": "bun test && bun run scripts/runtime-check.ts"
}
}
// src/server.ts
function json(data: unknown, status = 200): Response {
return Response.json(data, {
status,
headers: { "Cache-Control": "no-store" }
});
}
const server = Bun.serve({
port: Number(process.env.PORT ?? 3000),
async fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/health") {
return json({ ok: true, runtime: "bun" });
}
if (url.pathname === "/api/echo" && req.method === "POST") {
const body = (await req.json().catch(() => null)) as { message?: string } | null;
if (!body?.message) {
return json({ error: "message is required" }, 400);
}
return json({
message: body.message.trim(),
receivedAt: new Date().toISOString()
}, 201);
}
return json({ error: "not_found", pathname: url.pathname }, 404);
}
});
console.log(`Listening on ${server.url}`);
bun run dev
curl http://localhost:3000/health
curl -X POST http://localhost:3000/api/echo \
-H "Content-Type: application/json" \
-d '{"message":"hello from Bun"}'
Tests con bun:test
// src/message.ts
export function normalizeMessage(input: string): string {
return input.trim().replace(/\s+/g, " ");
}
export function createReply(input: string): { message: string; length: number } {
const message = normalizeMessage(input);
if (!message) throw new Error("message must not be empty");
return { message, length: message.length };
}
// src/message.test.ts
import { describe, expect, test } from "bun:test";
import { createReply, normalizeMessage } from "./message";
describe("message helpers", () => {
test("normalizes whitespace", () => {
expect(normalizeMessage(" hello bun ")).toBe("hello bun");
});
test("creates a reply payload", () => {
expect(createReply(" Claude Code ")).toEqual({
message: "Claude Code",
length: 11
});
});
test("rejects empty messages", () => {
expect(() => createReply(" ")).toThrow("message must not be empty");
});
});
bun test
bun test --watch
Revisión de compatibilidad Node
// scripts/runtime-check.ts
import { existsSync } from "node:fs";
import { join } from "node:path";
const checks = [
["package.json exists", existsSync(join(process.cwd(), "package.json"))],
["Bun global is available", typeof Bun !== "undefined"],
["fetch is available", typeof fetch === "function"],
["Buffer is available", typeof Buffer !== "undefined"]
] as const;
for (const [label, ok] of checks) {
console.log(`${ok ? "PASS" : "FAIL"} ${label}`);
}
if (checks.some(([, ok]) => !ok)) {
process.exit(1);
}
bun run check
Casos de uso concretos
El primer caso es una API interna o herramienta de administración. Bun.serve basta para /health, endpoints JSON, webhooks y demos locales.
El segundo caso es adopción incremental en un proyecto Node.js. Producción puede seguir en Node, mientras se prueban bun install, bun run o bun test para acortar el ciclo local.
El tercer caso es documentación o formación. Un ejemplo pequeño con servidor, curl y tests permite que el lector entienda el límite del runtime sin instalar un framework grande.
Errores frecuentes
Primero, no asumas compatibilidad Node total. Addons nativos, módulos node:* poco comunes, paquetes CommonJS antiguos y streaming deben probarse aparte.
Segundo, no migres una suite Jest grande de golpe. Mocking, snapshots, fake timers y DOM testing pueden necesitar ajustes.
Tercero, los scripts pueden cambiar de significado. En equipo, usa bun run dev de forma explícita y documenta el orden de flags como bun --watch run dev.
Cuarto, la velocidad no sustituye al plan de rollout. CI, Docker, despliegue, monitorización y rollback deben revisarse antes de producción.
CTA y nota de verificación
Para practicar, empieza con el cheatsheet gratuito. Para prompts reutilizables, patrones de CLAUDE.md y material de setup, compara la página de productos en inglés. Para adopción en equipo, usa training y consultoría.
Nota práctica: este workspace no tiene instalado bun, así que no se afirma una ejecución local. El ejemplo se puede verificar con bun run dev, los dos comandos curl, bun test y bun run check.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Workflow de Obsidian a CLAUDE.md con Claude Code
Convierte notas de trabajo de Obsidian en notas operativas de CLAUDE.md para no repetir contexto.
Claude Code Revenue CTA Routing: de artículos a PDF, Gumroad y consulta
Un flujo con Claude Code para dirigir lectores a PDF gratis, Gumroad o consulta según intención.
Reglas de handoff para equipos con Claude Code: evidencia, permisos, rollback e ingresos
Formato práctico para entregar trabajo de Claude Code con pruebas, permisos, rollback, PDF gratis, Gumroad y consulta.