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
Checklist de permisos antes de que Claude Code edite un sitio de cliente
Guía para agencias que quieren usar IA en landing pages sin tocar zonas sensibles.
Convierte tickets de soporte SaaS en pasos reproducibles con Claude Code
Flujo para transformar reportes vagos en pasos, evidencia y una nota útil para ingeniería.
Convierte tus notas viejas de Obsidian en instrucciones para Claude Code en 10 minutos
Rutina de 10 minutos para separar tus notas de Obsidian en hechos, decisiones y dudas, y darle a Claude Code instrucciones que sí funcionan.