workerd: el runtime de Workers
El motor open source escrito en C++ sobre V8 que ejecuta cada Worker: el mismo binario en tu máquina con wrangler dev que en producción, y por qué esa paridad elimina el clásico funciona-en-mi-máquina.
Cuando ejecutas wrangler dev en tu portátil y cuando despliegas a la red global de Cloudflare, tu código corre sobre exactamente el mismo motor: workerd. No es un simulador que imita el edge en local ni una versión recortada del runtime real; es el núcleo de ejecución literal de Workers, liberado como open source y embebido en tu herramienta de desarrollo. Interiorizar que ese binario es el contrato compartido entre local y producción es la base sobre la que se apoya todo lo demás de este nivel.
- Saber qué es
workerdy sobre qué tecnología está construido. - Entender por qué el mismo motor corre en local y en producción.
- Distinguir
workerddel envoltorio multi-tenant que añade el edge. - Situar
wrangler devy Miniflare v3 en la cadena de ejecución.
Qué es workerd
workerd es el runtime de JavaScript y WebAssembly que Cloudflare liberó como open source en 2022 bajo licencia Apache 2.0. Está escrito en C++ sobre el motor V8 —el mismo de Chrome y de Node—, pero el parecido con Node termina en el motor. Su unidad de ejecución no es el proceso ni el contenedor, sino el isolate: un espacio de memoria y seguridad aislado dentro de un único proceso de V8. Miles de isolates conviven en el mismo proceso del sistema operativo, cada uno con su propio heap y su contexto global, sin poder verse entre sí.
Esa decisión arquitectónica explica la propiedad más citada de Workers: no hay cold start. Arrancar un isolate cuesta una fracción de milisegundo, frente a las decenas o cientos de milisegundos de encender un contenedor o una función serverless tradicional. No hay máquina que levantar: solo un contexto nuevo dentro de un proceso que ya está caliente.
Y a diferencia de Node, workerd no usa libuv: implementa su propio bucle de eventos y su propia capa de entrada y salida en C++, diseñada desde cero para el modelo de peticiones del edge. Sobre ese motor ejecuta dos clases de código: JavaScript y WebAssembly. Lo segundo importa más de lo que parece, porque abre el runtime a lenguajes compilados —Rust, C, Go— que producen módulos Wasm y corren con rendimiento nativo dentro del mismo isolate, sin salir del modelo.
El Worker más simple, sin embargo, cabe en unas pocas líneas de JavaScript, y es exactamente lo que se carga en el isolate cuando arrancas:
export default {
async fetch(request: Request): Promise<Response> {
return new Response("Hola desde workerd");
},
};
Isolates, no procesos
La unidad de ejecución es un isolate de V8: heap y contexto global aislados dentro de un proceso compartido. Miles conviven sin verse.
Cero cold start
Crear un isolate cuesta una fracción de milisegundo, frente a las decenas de un contenedor. No hay máquina que encender.
Open source
Liberado en 2022 bajo Apache 2.0. El binario de producción es una versión de este mismo proyecto, no un primo cerrado.
Nanoservicios
Cada Worker es un servicio ligero que se compone con otros por bindings declarados: capacidades en vez de direcciones y credenciales.
La comparación con contenedores es la que mejor ilumina el modelo. Un contenedor aísla mediante el kernel: cada tenant recibe su propio espacio de procesos, su sistema de archivos y su pila de red, y arrancarlo cuesta tiempo y memoria.
Un isolate aísla dentro de V8: el límite lo pone el propio motor de JavaScript, que ya sabe impedir que un contexto lea la memoria de otro porque es exactamente lo que hace en cada pestaña del navegador. Por eso workerd puede meter miles de tenants en un solo proceso donde un modelo de contenedores metería unas pocas decenas. La densidad no es un detalle de eficiencia: es lo que hace económicamente viable ejecutar tu código en cientos de ubicaciones a la vez.
En su modo autónomo, workerd se configura con Cap’n Proto, un formato donde declaras servicios, sockets y los módulos que forman cada Worker. Rara vez escribirás este archivo a mano —Wrangler lo genera por ti—, pero verlo desnuda la naturaleza real del runtime:
using Workerd = import "/workerd/workerd.capnp";
const config :Workerd.Config = (
services = [ (name = "main", worker = .miWorker) ],
sockets = [ (name = "http", address = "*:8080", http = (), service = "main") ],
);
const miWorker :Workerd.Worker = (
modules = [ (name = "worker.js", esModule = embed "worker.js") ],
compatibilityDate = "2024-09-23",
);
Lo esencial es que este es el runtime literal, no una imitación: el binario que Cloudflare ejecuta en producción es una versión de este mismo proyecto open source. Que sea abierto tiene además una consecuencia estratégica: puedes autohospedar workerd fuera de Cloudflare, y esa transparencia es lo que convierte al runtime en un estándar auditable en lugar de una caja negra propietaria.
El gesto de abrirlo en 2022 fue deliberado y poco común: pocas empresas liberan el motor exacto que sostiene su negocio. La apuesta de Cloudflare era que un runtime destinado a ejecutar el código de medio mundo gana más como estándar inspeccionable que como secreto, igual que los navegadores comparten motores auditables. workerd no es, por tanto, una demo recortada del producto: es el producto, publicado.
El mismo motor en local y en producción
Aquí vive la idea central del nivel. Desde Wrangler 3, wrangler dev no simula el edge: descarga y ejecuta el binario real de workerd en tu máquina. La orquestación la hace Miniflare v3, que se encarga de todo lo que rodea a ese proceso:
- Descargar y arrancar el binario de
workerdcorrecto para tu plataforma. - Conectar cada binding a un backend local: KV y R2 sobre archivos, D1 sobre SQLite, colas en memoria.
- Persistir ese estado entre reinicios para que tus datos de prueba sobrevivan.
- Exponer un inspector compatible con las DevTools de Chrome para depurar con puntos de ruptura.
El contraste histórico es revelador. Miniflare v2 era una reimplementación en Node.js de las APIs de Workers: un simulador escrito en otro lenguaje que, por definición, podía divergir del comportamiento real. Miniflare v3 tiró esa reimplementación y pasó a conducir el workerd de verdad. El resultado es paridad por identidad: lo que ves en local es lo que ocurre en producción, porque es el mismo programa ejecutando tu programa.
wrangler dev # por defecto: un proceso workerd local
wrangler dev --remote # ejecuta en el edge real en vez de en local
wrangler dev --persist-to # dónde persistir KV, R2 y D1 locales
flowchart TD A[wrangler dev] --> B[Miniflare v3 orquesta] B --> C[proceso workerd local] D[red global de Cloudflare] --> E[proceso workerd en produccion] C --> F[mismo motor V8 y mismas APIs de runtime] E --> F
Que el runtime local sea el de verdad cambia cómo depuras. Un Response malformado, un stream que no cierra, una API que se comporta distinta según la compatibility date: todo eso se reproduce en tu portátil con exactitud, porque no hay una segunda implementación que pueda tener otro bug distinto. El ciclo de “reproduce el fallo en local, arréglalo, confía en que en producción pasa lo mismo” vuelve a ser fiable, que es precisamente lo que se había perdido en la era de los simuladores.
Y cuando el fallo solo aparece en producción —porque depende de datos o de tráfico reales—, la simetría sigue ayudando: wrangler tail transmite los logs del workerd de producción en vivo, con el mismo formato y las mismas trazas que verías en local. No cambias de mundo al pasar de tu portátil al edge; cambias de entorno dentro del mismo mundo.
En términos prácticos, ejecutar el workerd real en local te da cuatro garantías que un simulador nunca pudo ofrecer:
- Los mismos mensajes de error, con idénticos códigos y trazas que en producción.
- El mismo comportamiento ante compatibility dates y flags, sin sorpresas al desplegar.
- Soporte real de WebAssembly y de las APIs del runtime, no una aproximación.
- Un inspector equivalente al de producción para perfilar y poner puntos de ruptura.
workerd no es toda la red
Conviene no exagerar la paridad. workerd es el núcleo de ejecución, no la red completa. Producción envuelve ese núcleo con piezas que no viven en el binario: el supervisor multi-tenant que aísla a millones de clientes, el planificador que decide en cuál de los cientos de ubicaciones corre cada petición, el endurecimiento frente a ataques de canal lateral, la aplicación estricta de los límites de CPU y memoria, y los backends de almacenamiento distribuido reales. En local, esos backends son simulaciones sobre tu disco.
La distinción es qué eje comparten y cuál no, y conviene tenerla explícita:
- Eje del lenguaje (idéntico): las APIs, el modelo de isolates y el comportamiento de las compatibility dates. Vive en
workerd, así que es igual en tu portátil y en el edge. - Eje del entorno (distinto): datos reales, latencia entre ubicaciones, escala, multi-tenencia y almacenamiento distribuido. Solo existe de verdad en la red de producción.
De ahí la regla que gobierna el flujo de trabajo: la lógica se depura en local con plena confianza, porque el eje que la determina es idéntico; el rendimiento y los datos reales se validan en un entorno de staging, porque pertenecen al eje que no puedes reproducir en una sola máquina.
La paridad es semántica, no operativa. Que el motor sea el mismo garantiza que un Response, un stream o una compatibility date se comporten igual en tu portátil y en el edge. No garantiza la latencia entre ubicaciones ni el estado de tus datos de producción: eso pertenece al entorno, no al runtime. Confundir los dos ejes lleva a probar en local cosas que solo tienen sentido en la red real, y a desconfiar en producción de cosas que ya quedaron demostradas en local.
Durante veinte años, “funciona en mi máquina” fue una enfermedad crónica del desarrollo backend, y su causa raíz casi siempre era la misma: el entorno local y el de producción eran implementaciones distintas que fingían ser iguales. Un servidor de desarrollo en un lenguaje, un runtime de producción en otro; dos bases de código imitándose y divergiendo en los detalles. Cloudflare atacó el problema por la raíz al hacer open source el motor real y embeberlo en la herramienta de desarrollo. Cuando depuras un Worker en tu portátil, tu JavaScript se compila al mismo bytecode, corre sobre el mismo V8 y llama a la misma superficie de APIs implementada en el mismo C++ que en el edge. Las diferencias que quedan son ambientales —qué datos hay, cuánta latencia, cuánta escala— y nunca semánticas. Esa inversión, pasar de la paridad por imitación a la paridad por identidad, es lo que convierte el desarrollo en el edge en algo fiable: el runtime deja de ser una caja negra remota y se vuelve un binario que tienes delante, el mismo que Cloudflare corre por ti a milisegundos de cada usuario del planeta. Es, además, una lección de diseño reutilizable: la mejor forma de garantizar que dos entornos se comporten igual no es documentar sus semejanzas, sino hacer que sean, literalmente, el mismo código.
- Ejecuta
wrangler deven un proyecto y observa en la salida cómo arranca un procesoworkerd; localízalo conpsmientras corre. - Explica con tus palabras la diferencia entre la simulación de Miniflare v2 y la ejecución del
workerdreal en Miniflare v3. - Enumera tres diferencias entre local y producción que siguen existiendo pese a compartir motor, y clasifícalas como ambientales, no semánticas.
- Abre el repositorio de
workerdy localiza el formato de configuración Cap’n Proto: identifica dónde se declaran losservicesy lossockets.