Qué es celld y cómo ejecutar Durable Objects sin Cloudflare
Un repositorio con 2.827 estrellas y una semana de vida. La primera release, la v0.0.1, se publicó el 2 de agosto de 2026. La v0.1.0 llegó tres días después.
Y en su portada hay un gráfico que explica esas estrellas mejor que cualquier README: mil objetos con estado en Cloudflare Durable Objects cuestan unos 4.150 dólares al mes. Los mismos mil, en celld, cuestan 49.
Antes de que saques la calculadora: no es magia, y no estás comparando exactamente lo mismo. Pero el número es real, viene con su metodología escrita al lado y detrás hay gente que sabe lo que hace. Las contribuciones al proyecto se envían por correo a ry@deno.com, así que ya sabes de quién estamos hablando: Deno Land Inc., la casa de Ryan Dahl.
celld es un demonio open source que ejecuta Cloudflare Workers y Durable Objects en tus máquinas. Mismo código, mismo wrangler.jsonc, otro sitio donde se ejecuta.
Esto es lo que vas a encontrar:
- Qué es un Durable Object y por qué es una idea tan buena aunque nunca hayas tocado Cloudflare
- Cómo un sistema distribuido puede coordinarse sin consenso, sin protocolo de membresía y sin plano de control
- Los números de verdad: latencia, densidad, coste por celda y qué hay detrás de cada cifra
- Un ejemplo completo, del
wrangler.jsoncal nodo levantado - Qué APIs de Cloudflare funcionan y cuáles fallan (con la tabla oficial)
- El ángulo que más te va a interesar: una celda por agente de IA
- Cómo se prueba que un sistema así no pierde escrituras (esta parte es un espectáculo)
- Y lo que no hace: es un alpha, y sus autores lo dicen antes que tú
¿Qué es un Durable Object y por qué importa aunque no uses Cloudflare? ¶
Un Durable Object es un servidor diminuto con un nombre y su propia base de datos SQLite privada. Eso es todo. Le pides el objeto llamado sala-42 y siempre te atiende el mismo, con los mismos datos dentro.
La parte que lo cambia todo es esta: ese objeto se ejecuta en un solo hilo. Dos peticiones a la misma celda nunca se ejecutan en el mismo instante. Una segunda petición solo puede intercalarse mientras la primera está en un await, y las operaciones de almacenamiento son síncronas, así que un storage.put() no se intercala jamás.
¿Qué significa eso en la práctica? Que desaparecen las condiciones de carrera que llevas toda la vida esquivando con transacciones, locks optimistas y reintentos. No hay dos escritores. Hay uno. Punto.
Piensa en el modelo clásico: una base de datos gorda en el centro y veinte procesos sin estado peleándose por escribir en ella. Cada funcionalidad que añades es una oportunidad nueva para un deadlock, y cuando esa base de datos se cae, se cae todo. El modelo de Durable Objects le da la vuelta: la aplicación se parte en celdas desde el minuto uno. Una por usuario. Una por documento. Una por sala de chat. Una por partida. Una por agente.
Como cada celda es su propia base de datos, el sharding no es una decisión que tomas en el mes catorce cuando ya duele: viene de fábrica. Y el radio de explosión de un fallo es una celda, no el sistema.
El estado de una celda tiene cuatro modos, y conviene tenerlos claros porque de ahí sale toda la economía del asunto:
| Estado | Qué significa | Qué cuesta |
|---|---|---|
| Activa | Residente en memoria y trabajando | CPU + RAM del nodo |
| Idle | Residente en memoria, esperando | Solo RAM (~4 MB) |
| Hibernada | Fuera de memoria, pero mantiene sus WebSockets y su nodo | Casi nada |
| Inactiva | Solo un objeto en S3 | Prácticamente cero |
Toda celda nace inactiva. Y aquí está el detalle que la gente pasa por alto: la memoria no sobrevive a esas transiciones. El constructor se ejecuta otra vez en el siguiente evento. Una celda hibernada arranca igual que un cold start; lo único que la distingue es que sus clientes WebSocket siguen conectados y que no ha cambiado de nodo.
El propio equipo de celld es explícito sobre de quién es el mérito: el modelo de Durable Objects “es uno de los mejores primitivos que se le han dado a los sistemas distribuidos en años”, y ese diseño es de Kenton Varda y del equipo de Cloudflare Workers. Lo llaman “una carta de amor a su idea”.
🔑 Un Durable Object no es una caché ni un microservicio. Es un objeto con nombre, con memoria, con disco propio y con un único hilo. Si entiendes eso, entiendes por qué la gente lleva años queriendo ejecutarlo fuera de Cloudflare.
¿Qué es celld exactamente? ¶
celld es V8 + SQLite + LTX. Sus autores lo resumen así, y no hay mucho más que añadir.
Es un binario estático de 58 MB, escrito en Rust, con licencia Apache-2.0. Cada nodo lleva V8 incrustado y ejecuta bundles de Wrangler. Cada celda es una base de datos SQLite. Y el estado de cada celda se replica de forma continua a un bucket compatible con S3 —el tuyo— usando LTX, que es el formato de réplica de Litestream, obra de Ben Johnson.
La instalación es de una línea:
curl -fsSL https://celld.dev/install.sh | sh
O con Docker, si prefieres no tocar el PATH:
docker run --rm ghcr.io/denoland/celld --version
Lo que más me llama la atención de su portada es la tercera opción de instalación que ofrecen, que ya te dice mucho sobre para quién está pensado esto en 2026:
❯ create a distributed chat app with vite, use celld.dev and exe.dev, 2 VMs
Sí: “díselo a tu agente”. No es una broma, es la tercera pestaña de la home.
El binario incluye el replicador, así que un nodo no necesita ningún proceso externo. Si tu proyecto tiene código de Worker, celld deploy necesita esbuild en el PATH. Si es un proyecto de solo assets estáticos, ni eso.
Antes de decirle a un agente que te monte una app distribuida, dale un método
Ese prompt de la portada de celld es real, y un agente suelto sobre infraestructura con estado hace estropicios caros. Aquí recorres el ciclo completo de Spec Driven Development con OpenSpec sobre un proyecto real y en modo asistido: proposal, spec, diseño, tareas y archivar.
Entra en el curso gratis →¿Cómo se coordina un clúster sin consenso? ¶
Con un truco tan simple que da rabia no haberlo pensado: el bucket es el coordinador.
No hay protocolo de membresía. No hay detector de fallos. No hay servicio de consenso. No hay Raft, ni Paxos, ni etcd, ni ZooKeeper. La propiedad de una celda es un registro en tu bucket, reclamado con una sola escritura atómica.
Un nodo quiere servir la celda sala-42: hace un compare-and-swap contra el objeto de propiedad en S3. Si gana, es suyo, con un número de época que actúa de valla. Si un nodo pierde su lease y aun así intenta escribir, la época lo bloquea. Un escritor por época, siempre.
Para añadir un nodo a la flota, apuntas el nodo al bucket. No hay comando join, no hay lista fija de miembros:
celld \
--bucket "$CELLD_BUCKET" \
--endpoint "$S3_ENDPOINT" \
--region "$AWS_REGION" \
--listen 0.0.0.0:8080 \
--advertise node-a.internal:8080
Y la parte que hace que esto sea confiable de verdad: celld no confirma una escritura antes de que el dato esté en el bucket. Eso es lo que significa RPO=0 (Recovery Point Objective igual a cero). La caída de un nodo no puede perder una escritura confirmada, porque la confirmación llegó después de la durabilidad, no antes. Le llaman output gate, y desde la v0.0.2 está activado por defecto: las respuestas HTTP, los frames de WebSocket salientes y los broadcasts se retienen hasta que la réplica está hecha.
El precio de esa promesa es honesto y está escrito: una escritura durable cuesta un viaje de ida y vuelta al bucket, unos 90 ms si el bucket está en tu región. No hay forma de bajar de ahí sin dejar de cumplir la promesa. Lo que sí hacen es agrupar: varias escrituras concurrentes a una misma celda se juntan en una sola subida.
⚠️ Ojo con la lectura fácil de “sin consenso”. No es que hayan resuelto el consenso distribuido: es que han delegado la parte difícil en S3, que ya te da compare-and-swap atómico y durabilidad. Es una decisión de arquitectura brillante, no un atajo. Pero significa que tu bucket es el punto único del que cuelga absolutamente todo.
Ese bucket contiene los despliegues, las réplicas SQLite, los registros de propiedad, los leases de los nodos y el secreto de autenticación entre pares. Quien tiene las credenciales del bucket, controla la flota. Trátalas como acceso de administrador, porque lo son.
¿Cuánto cuesta de verdad frente a Cloudflare? ¶
Aquí es donde el gráfico de la portada hace su trabajo. Estos son los números que publican, con su metodología:
| Celdas residentes | Durable Objects | celld |
|---|---|---|
| 10 | ~$42/mes | ~$49/mes |
| 100 | ~$415/mes | ~$49/mes |
| 1.000 | ~$4.150/mes | ~$49/mes |
| 10.000 | ~$41.500/mes | ~$486/mes |
| 100.000 | ~$415.000/mes | ~$4.856/mes |
El modelo es transparente por los dos lados. Para Cloudflare: plan Workers Paid, 5 dólares al mes más 4,15 dólares por celda residente y mes, que sale de su tarifa oficial de 12,50 dólares por millón de GB-s de duración. Para celld: nodos enteros de 48 dólares con 8 GB (precio de lista de DigitalOcean en us-east), cada uno con un tope de 1.000 celdas residentes, y la capacidad crece a saltos.
Fíjate en la forma de las dos curvas, que es lo importante. Cloudflare cobra por celda; celld cobra por nodo. Por eso a escala pequeña Cloudflare gana (y en su plan gratuito, gana de calle: 13.000 GB-s al día y 100.000 peticiones diarias cubren de sobra un proyecto de juguete). Y por eso a partir de la primera centena la línea de celld se aplana y la otra sigue subiendo.
Hay una frase en el gráfico que resume el punto de inflexión con una precisión casi cruel: “1,2 celdas residentes — se agota la duración incluida de DO”. Con algo más de una celda encendida todo el mes, ya te saliste del plan incluido.
Un matiz que ellos mismos ponen y que no deberías saltarte: eso es coste base antes de la carga de trabajo. El tráfico de tu aplicación y sus escrituras añaden cómputo y operaciones de bucket por los dos lados. Nadie te está prometiendo 49 dólares finales.
Y otro matiz que no está en el gráfico y que te va a costar más caro que la factura: en la columna de Cloudflare, el sueldo del que mantiene la infraestructura está incluido. En la de celld, no. Si tienes una flota de diez VMs, tienes diez VMs que parchear, monitorizar y despertar a las tres de la mañana. Eso lo hablamos en el apartado de cuándo tiene sentido.
Leer la letra pequeña de un modelo de precios antes de adoptar algo es de las habilidades peor pagadas y más rentables que existen. Cada domingo juntamos 12 recursos sobre cómo está cambiando el oficio con IA. Ya somos +6.700 developers.
Apúntate gratis →¿Cómo se levanta una celda desde cero? ¶
Con el mismo código que escribirías para Cloudflare. Literalmente el mismo. Este es el ejemplo counter del repositorio, sin tocar una coma:
export class Counter {
constructor(state, env) { this.state = state; }
async fetch(request) {
// No hace falta transacción: esta celda tiene un solo escritor
let n = (await this.state.storage.get("n")) ?? 0;
n++;
await this.state.storage.put("n", n);
return new Response(JSON.stringify({ n, url: request.url }), { status: 200 });
}
}
export default {
async fetch(request, env) {
// idFromName: el nombre ES la dirección de la celda
const id = env.COUNTER.idFromName("room-42");
return env.COUNTER.get(id).fetch(request);
}
};
Ese get/put sin transacción es el ejemplo perfecto de lo que te ahorra el modelo. En una arquitectura normal, ese incremento entre dos peticiones concurrentes es un bug clásico de lectura-modificación-escritura. Aquí no puede serlo.
Su configuración es un wrangler.jsonc estándar:
{
"name": "counter",
"main": "index.js",
"compatibility_date": "2026-01-01",
"durable_objects": { "bindings": [{ "name": "COUNTER", "class_name": "Counter" }] },
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["Counter"] }]
}
Configuras el bucket con la cadena de credenciales estándar de AWS. Para R2 de Cloudflare, por ejemplo:
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_REGION=auto
export S3_ENDPOINT=https://ACCOUNT_ID.r2.cloudflarestorage.com
export CELLD_BUCKET=s3://YOUR-BUCKET
(Sí: puedes ejecutar celld contra el propio R2 de Cloudflare. Tiene su gracia.)
Y despliegas:
celld deploy . \
--bucket "$CELLD_BUCKET" \
--endpoint "$S3_ENDPOINT" \
--region "$AWS_REGION"
Cuando ya tienes varios nodos en marcha, celld diagnose lee los leases del bucket y sondea a cada par vivo con una petición firmada. No pide leases ni cambia la propiedad de nada, así que es seguro lanzarlo en producción. El informe distingue registros caducados, direcciones anunciadas inseguras o mal formadas, pares inalcanzables, fallos de autenticación y versiones de protocolo que no casan.
Es el tipo de herramienta que solo escribe alguien que ya ha depurado una flota a ciegas.
¿Qué APIs de Cloudflare funcionan y cuáles no? ¶
La regla de alcance que se han puesto es clara: si Cloudflare construye una función sobre Durable Objects, celld puede tenerla; si está sobre otro primitivo, está fuera.
Por eso D1 está en la hoja de ruta (una base de datos D1 es un Durable Object con una API SQL por encima, y la parte difícil ya la tienen), y KV y R2 no lo están: KV es una caché global con consistencia eventual y R2 es almacenamiento de blobs. celld se ejecuta sobre almacenamiento de blobs; no lo proporciona.
| Superficie | Estado en celld |
|---|---|
Module Workers, fetch, JS RPC, service bindings |
Completo |
| Durable Objects (SQLite, alarmas, WebSockets hibernables) | El núcleo del proyecto |
Assets estáticos (_headers, _redirects, run_worker_first) |
Completo, incluso sin Worker |
| Streams, Encoding, WebAssembly, estándares web | Completo, con huecos menores |
| Web Crypto | Parcial: faltan deriveKey, wrapKey y verificación no-HMAC |
| Compatibilidad Node.js | Parcial: assert, async_hooks, buffer, path, stream, util |
Handlers scheduled (cron), queue, tail, email |
No |
| KV, R2, Cache API, Workers AI, Vectorize, HTMLRewriter | Fuera de alcance |
ctx.facets, sockets TCP, setInterval |
No |
wrangler.toml |
No: solo wrangler.jsonc o wrangler.json |
Su compromiso con los huecos me parece la mejor señal de madurez de todo el proyecto: “una configuración o binding que no esté disponible debe fallar de forma ruidosa, en el despliegue o en el primer uso. Un hueco de compatibilidad silencioso es un bug”. Si tu wrangler.jsonc lleva una clave que celld no soporta —routes, kv_namespaces, triggers—, el despliegue se detiene y te dice cuál es.
Y para que veas que no es marketing: en su propia documentación marcan los huecos silenciosos que aún tienen, con nombre y apellidos. connect() de cloudflare:sockets devuelve un stub inerte en lugar de lanzar una excepción, y los módulos node: no implementados hacen lo mismo en vez de fallar en el import. Están listados como defectos conocidos, no escondidos.
¿Una celda por agente de IA? ¶
Esta es la parte que más te va a interesar si tu trabajo de 2026 se parece al mío.
Piensa en lo que necesita un agente de IA para funcionar en producción: memoria persistente que sobreviva a la petición, un único hilo para que dos mensajes no le pisen el estado, alarmas para que pueda despertarse solo dentro de una hora, WebSockets para hablar con el cliente en tiempo real, y coste casi cero cuando no hace nada.
Ahora vuelve a leer la lista de lo que es una celda. Es exactamente eso.
Su propia documentación lo pone como el cuarto caso de uso: “haces una celda por cada usuario, cada documento, cada sala de chat o cada agente de IA”.
El ejemplo de alarmas del repositorio es un agente que se programa a sí mismo:
export class Agent {
constructor(state, env) { this.state = state; }
async fetch(request) {
const url = new URL(request.url);
if (url.pathname === "/arm") {
// Se despierta sola dentro de 2 segundos, sin cron externo
await this.state.storage.setAlarm(Date.now() + 2000);
return new Response(JSON.stringify({ armed: true }));
}
const fires = (await this.state.storage.get("fires")) ?? 0;
return new Response(JSON.stringify({ fires }));
}
async alarm(info) {
const fires = (await this.state.storage.get("fires")) ?? 0;
await this.state.storage.put("fires", fires + 1);
await this.state.storage.put("lastRetry", info.retryCount);
}
}
Sin cron, sin cola, sin worker de fondo, sin Redis. Una alarma durable dentro del propio objeto que la necesita, con contador de reintentos incluido.
Y hay una pieza experimental que apunta directo a este terreno: el Worker Loader (lo llaman Code Mode). Lo activas con CELLD_WORKER_LOADER=LOADER y tu Worker recibe env.LOADER, con el que puede arrancar isolates aislados en tiempo de ejecución para ejecutar código que le llega en caliente. Límites de workerd: 64 MiB de código, 1 MiB de env, y puedes pasarle globalOutbound: null para dejarlo sin salida a red.
Un sandbox por invocación, dentro de tu infraestructura. Si has estado siguiendo cómo se está montando la arquitectura de los agentes de IA, ya ves por dónde va.
💡 Si solo te llevas una idea de todo el artículo: el mejor primitivo que existe hoy para “un agente con memoria y sin condiciones de carrera” acaba de dejar de estar atado a un único proveedor.
Con la reserva importante de siempre: esto es un alpha, y su propia página de seguridad dice que no es seguro para uso multitenant hostil. Un sandbox experimental sobre un runtime alpha no es donde quieres ejecutar código de terceros todavía.
Construye agentes con criterio
Dónde encaja el estado dentro de la arquitectura de un agente
Una celda por agente resuelve el dónde vive la memoria, pero no el resto. Verás los seis niveles de arquitectura — tools, guardarraíles, memoria, skills, MCP y orquestación — con código y sistemas multiagénticos revisados por otro modelo.
Ver el método entero →Masterclass en directo · 6 niveles de arquitectura · Suscripción Web Reactiva Premium
¿Cómo se prueba que un sistema así no pierde escrituras? ¶
Su página de testing es, sin exagerar, el mejor contenido técnico de todo el sitio. Y merece la pena contarla porque es aplicable a cosas que tú sí construyes.
Hacen tres promesas y atacan cada una en la capa donde el fallo se vería mejor.
Uno: conformidad diferencial. Ejecutan cada programa de Workers y Durable Objects dos veces: una en workerd (el binario de runtime que Cloudflare opera en producción) y otra en celld, sobre bytes idénticos. Las dos salidas tienen que ser iguales. Eso demuestra dos cosas a la vez: que el programa es código real de Cloudflare, porque workerd lo acepta, y que celld cumple el contrato, porque coincide. Su frase: “un test no puede coincidir con nuestro propio runtime por accidente”.
Dos: simulación determinista. Los bugs peligrosos viven en la coordinación: un crash durante un traspaso de propiedad, una renovación de lease que compite con una toma de control, una alarma que se dispara contra una celda medio restaurada. Esas ventanas duran nanosegundos y se abren muy poco, así que esperar a que aparezcan no es un plan.
Su solución: el protocolo de coordinación es un núcleo de decisión puro, sin E/S propia. El reloj, la aleatoriedad y el object store son interfaces, y un simulador conduce el núcleo. El store simulado inyecta latencia, carreras de compare-and-swap y respuestas perdidas; los relojes se desincronizan; un nodo puede caerse en cada await. Cada ejecución la conduce un planificador con semilla, así que un fallo no es una casualidad: la semilla lo reproduce exacto, siempre. Los protocolos centrales han pasado por millones de planificaciones distintas.
Y el detalle que me ganó: también prueban los verificadores. Ejecutan variantes del protocolo rotas a propósito contra las propiedades, y las propiedades tienen que encontrar el daño. “Una suite que se queda verde contra un protocolo roto es una suite rota.”
Tres: flotas reales. Porque la simulación no ve la latencia de cola real de S3, ni el comportamiento del kernel, ni V8 bajo presión de memoria. Tienen un laboratorio permanente de VMs estándar con un bucket real, y ahí inyectan fallos entre pasadas de verificación: matan un nodo con SIGKILL en mitad de un stream de escritura y le borran la base de datos local, para que la recuperación solo pueda venir del bucket. Congelan un nodo propietario, escriben en sus celdas desde otros y lo descongelan. Cortan a un nodo del bucket y este se autovalla, porque un nodo que no puede replicar no debe poseer celdas. Estrangulan el bucket para que responda 429 a todo.
Los números que publican, cada uno con su condición de medida:
- La valla de época aguanta bajo contención: 500 reclamantes intentando poseer las mismas celdas a la vez, 5.500 intentos, un escritor por época, cero violaciones.
- Una petición residente en caliente es local: cero operaciones de bucket, p50 ~1,1 ms y p99 ~7 ms. Solo una activación en frío toca el almacenamiento.
- Diez nodos pequeños aguantaron escala real: una flota de diez nodos de 4 vCPU y 8 GB sostuvo 10.000 celdas residentes y 20.000 conexiones WebSocket concurrentes. Pararon dos de los diez y los datos de todas las celdas volvieron a estar disponibles en otro nodo en ~11 s en la cola.
Y luego está la parte que casi nadie publica: los bordes donde su política falla. El más claro es el margen de reserva. Una flota llena hasta su límite de celdas residentes no tiene sitio para las celdas de un nodo perdido, así que un fallo de más de un nodo con la flota al límite degrada el servicio. Lo miden por los dos lados, el bueno y el rojo, “porque esa medición forma parte del trabajo”.
Guardan una ejecución en rojo con el mismo cuidado que una en verde. Cuando veas a alguien hacer eso con su propio producto, préstale atención.
¿Cuáles son los números de rendimiento y qué hay detrás? ¶
Estos son los que salen en portada. Los pongo con su letra pequeña al lado, porque sin ella no valen nada:
| Métrica | Valor | Condición real |
|---|---|---|
| Petición sin estado p50/p99 | 0,2 / 0,3 ms | Un nodo, celdas triviales, portátil Apple M sobre loopback |
| Throughput sin estado | ~94.000 req/s por hilo | Mismo escenario de laboratorio |
| Despertar una celda hibernada | ~4 ms | Mismo escenario; en un nodo de 2 vCPU la activación p50 sube a 35,9 ms |
| Escritura durable | ~90 ms | Flota de 4 vCPU / 8 GB, bucket en la misma región |
| Failover tras pérdida de nodo | ~20 s | Con cero escrituras confirmadas perdidas |
| RAM por celda residente | 4 MB | — |
| Densidad | 1.000 celdas por nodo de 8 GB | Tope duro configurable en admisión |
La diferencia entre 4 ms y 35,9 ms para lo mismo, según si es un M4 o una VM de 2 vCPU, es exactamente por qué hay que leer las condiciones. Ellos las escriben. Su frase, otra vez, es buena: “un número sin sus condiciones no vale nada”.
Desde la v0.1.0, el límite de celdas residentes es un tope duro que se aplica en la admisión, y el descarte por presión se decide por RSS y CPU. El descarte por RSS viene activo al 80% de la memoria disponible (el límite del cgroup si estás en contenedor). Un nodo lleno rechaza colocaciones nuevas en lugar de desalojar a una celda residente, que es justo la decisión que quieres cuando el sistema va apretado.
Guardar la ejecución en rojo con el mismo cuidado que la verde es una lección que sirve mucho más allá de los sistemas distribuidos. Cada domingo compartimos lo que vamos aprendiendo con la IA en el día a día del desarrollo, y los suscriptores aportan lo suyo. Gratis, desde 2018.
Quiero esa dinamita 🧨¿Qué NO hace celld todavía? ¶
Voy a copiarles el tono, porque su página de limitaciones es más honesta que la mayoría de los posts que leerás sobre esto:
- Es un alpha. Los arreglos de seguridad van solo a la última release; los builds alpha antiguos no reciben parches.
- No es seguro para uso multitenant hostil. Dicho por ellos, en su página de seguridad.
- Una flota ejecuta una sola aplicación. No hay planificador multitenant, ni servicio de cuentas, ni ingress gestionado, ni capa de colocación global.
- El protocolo entre pares no termina TLS. El tráfico entre nodos es HTTP plano. Va autenticado con HMAC, firma del cuerpo, límite de reloj y protección contra reenvío, pero no cifrado. Tienes que ponerlo en una red privada o en una malla como WireGuard o Tailscale, y terminar el TLS público en tu proxy de entrada. Una IP pública literal la rechaza salvo que pases
--unsafe-public-advertisea propósito. - Las credenciales del bucket son la autoridad administrativa. Y solo lee las variables
AWS_*o credenciales gestionadas: no lee perfiles de~/.awsni sesiones de SSO. - Un WebSocket saliente no sobrevive a un movimiento de celda. Guarda la intención de conexión en el storage y reconecta tras la activación.
- No hay Windows y los Mac con Intel no tienen binarios precompilados (compilar desde el código funciona).
- Las actualizaciones son manuales. El instalador guarda releases inmutables detrás de un puntero
current; el rollback es volver a un SHA anterior. No hay agente de actualización automática. - Los pull requests están desactivados. Este es peculiar y merece leerse entero: “los agentes de código hacen demasiado fácil enviar un cambio grande y sin contexto que le cuesta al mantenedor más tiempo del que ahorra”. Las contribuciones se envían por correo con
git format-patchary@deno.com.
Ese último punto es una señal de los tiempos que da para su propio artículo. Un proyecto de 2026, con 2.800 estrellas en su primera semana, cerrando la puerta de las PRs porque la avalancha de parches generados por IA no le compensa.
¿Deberías usarlo? ¶
Depende de dónde estés en esta tabla:
| Tu situación | ¿celld? | Por qué |
|---|---|---|
| Aprendiendo el modelo de Durable Objects | Sí, en local | Levantas una flota en tu portátil y tocas el modelo sin tarjeta de crédito |
| Proyecto pequeño ya en Cloudflare que funciona | No | El plan gratuito te cubre y no tienes nada que ganar |
| Cientos o miles de objetos con estado y factura que escuece | Ahora sí es interesante | Es exactamente la curva que ataca, pero espera a que salga del alpha |
| Requisito de soberanía del dato o de nube concreta | Muy interesante | El dato vive en tu bucket, en tu jurisdicción |
| Miedo a la dependencia de un proveedor | Sí, como plan B | El mismo código se ejecuta en los dos sitios: esa es la palanca |
| Producción crítica hoy | Todavía no | Alpha, sin TLS entre pares, actualizaciones manuales |
| SaaS multitenant con código de clientes | No | Lo desaconsejan sus propios autores |
| Sin nadie que sepa operar VMs | No | El ahorro de la factura te lo comes en operaciones |
Mi lectura: el valor de celld hoy no es tanto ahorrarte la factura como quitarle el candado al modelo. Durable Objects lleva años siendo una de las mejores ideas de la computación distribuida y también una de las más atadas: si la adoptabas, adoptabas Cloudflare entero. Que exista una implementación abierta que pasa tests diferenciales contra el workerd real cambia esa conversación aunque nunca llegues a desplegarla.
Es la misma dinámica que ya se ha visto en otros rincones del oficio: en el momento en que aparece una alternativa open source creíble, lo que cambia primero no es dónde despliegas, sino cuánto poder de negociación tienes. Algo parecido pasó con las alternativas open source a GitHub, y sigue pasando cada vez que alguien libera una pieza que era exclusiva.
Y si quieres probarlo sin gastar un euro, tienes camino: instala el binario, apúntalo a un bucket R2 en el plan gratuito de Cloudflare, despliega el ejemplo counter y mira la respuesta subir. Tardas menos que en leer este artículo. Si además andas explorando dónde alojar tus experimentos, la comparativa de hostings gratuitos para programadores te da más sitios donde probar.
¿Cuántas de las condiciones de carrera que arreglaste este año no habrían existido si cada pieza de estado hubiera tenido su propio hilo?
TL;DR ¶
- 🧬 celld ejecuta Cloudflare Workers y Durable Objects en tus máquinas: mismo código, mismo
wrangler.jsonc, binario estático de 58 MB en Rust, Apache-2.0, de Deno Land Inc. - 🪣 El bucket S3 es el coordinador: sin consenso, sin Raft, sin protocolo de membresía. La propiedad de cada celda es un compare-and-swap con valla de época, y un nodo nuevo se une apuntando al mismo bucket.
- 💸 A escala se aplana la curva: 1.000 celdas residentes son ~$4.150/mes en Durable Objects y ~$49/mes en celld, porque uno cobra por celda y el otro por nodo. Por debajo de ~10 celdas, Cloudflare gana.
- 🔒 RPO=0 real: no confirma una escritura hasta que está en el bucket. Cuesta ~90 ms por escritura durable, y a cambio matar un nodo con
SIGKILLno pierde nada. - 🤖 Una celda por agente de IA es el caso de uso que lo pone todo en su sitio: memoria persistente, un solo hilo, alarmas durables, WebSockets hibernables y coste casi cero cuando duerme.
- ⚠️ Es un alpha con la letra pequeña escrita: sin TLS entre pares, sin KV ni R2, sin Windows, actualizaciones manuales, no apto para multitenant hostil y con las pull requests desactivadas a propósito.
Preguntas frecuentes ¶
¿Qué es celld? ¶
celld es un demonio open source, escrito en Rust y con licencia Apache-2.0, que ejecuta Cloudflare Workers y Durable Objects en máquinas propias. Cada objeto (una “celda”) es su propia base de datos SQLite, replicada de forma continua a un bucket compatible con S3. Lo desarrolla Deno Land Inc. y su primera release pública, la v0.0.1, es del 2 de agosto de 2026.
¿Qué es un Durable Object de Cloudflare? ¶
Es un objeto de servidor con un nombre y su propia base de datos SQLite privada, que se ejecuta en un único hilo. Dos peticiones al mismo objeto nunca se ejecutan a la vez, así que su estado no puede sufrir condiciones de carrera. Se usa para modelar una sala de chat, un documento colaborativo, la sesión de un usuario o un agente de IA.
¿celld es compatible al 100% con Cloudflare Workers? ¶
No, y lo dice de forma explícita. Cubre module Workers, fetch, JS RPC, service bindings, Durable Objects con SQLite y alarmas, WebSockets hibernables y assets estáticos. Quedan fuera KV, R2, Cache API, Workers AI, HTMLRewriter, los handlers scheduled/queue/email y wrangler.toml. Una clave o binding no soportado detiene el despliegue con un error que nombra la clave.
¿Cuánto cuesta celld frente a Durable Objects? ¶
celld en sí es gratis: pagas los nodos y el bucket. Su modelo publicado usa nodos de 48 dólares con 8 GB (DigitalOcean, us-east) con un tope de 1.000 celdas residentes cada uno. Para 1.000 celdas residentes eso son unos 49 dólares al mes frente a unos 4.150 en Durable Objects. Es coste base: el tráfico y las escrituras suman por los dos lados.
¿Cómo se instala celld? ¶
Con curl -fsSL https://celld.dev/install.sh | sh, que descarga el binario estático de 58 MB, o con la imagen de contenedor ghcr.io/denoland/celld para Linux x86-64 y ARM64. Si tu proyecto tiene código de Worker, necesitas esbuild en el PATH. Los proyectos de solo assets estáticos no lo necesitan.
¿Cómo coordina celld varios nodos sin un plano de control? ¶
El bucket compatible con S3 hace de coordinador. La propiedad de cada celda es un registro en el bucket que un nodo reclama con una escritura atómica de compare-and-swap, protegida por un número de época. No hay protocolo de membresía, ni detector de fallos, ni servicio de consenso. Para añadir un nodo a la flota, se apunta ese nodo al mismo bucket.
¿Se pierden escrituras si se cae un nodo? ¶
No, si el output gate está activo (lo está por defecto desde la v0.0.2). celld no confirma una escritura hasta que el dato está en el bucket, así que el objetivo de punto de recuperación es cero (RPO=0). En sus pruebas de fallo matan nodos con SIGKILL en mitad de un stream de escritura y borran la base de datos local, y todas las escrituras confirmadas vuelven desde el bucket.
¿Se puede usar celld en producción? ¶
Sus autores lo describen como un alpha y desaconsejan el uso multitenant hostil. Además, el protocolo entre nodos no termina TLS (necesita red privada o una malla como WireGuard o Tailscale), las actualizaciones son manuales y los arreglos de seguridad solo llegan a la última release. Para producción crítica hoy, todavía no.
¿Sirve celld para ejecutar agentes de IA? ¶
Encaja bien con el patrón de una celda por agente: memoria persistente entre peticiones, un solo hilo que evita condiciones de carrera en el estado, alarmas durables para que el agente se despierte solo, WebSockets hibernables y coste casi nulo mientras duerme. Tiene además un Worker Loader experimental (Code Mode) que permite arrancar isolates aislados en tiempo de ejecución.
¿Qué relación tiene celld con Cloudflare? ¶
Ninguna oficial: es un proyecto independiente de Deno Land Inc. que reimplementa el modelo. Su equipo atribuye el diseño de Durable Objects a Kenton Varda y al equipo de Cloudflare Workers y describe el proyecto como “una carta de amor a su idea”. Su propia página, de hecho, la sirve un Cloudflare Worker.
Fuentes ¶
- Web oficial de celld
- Documentación de celld
- Página de compatibilidad con Cloudflare, API por API
- Cómo se prueba celld: conformidad, simulación y flotas reales
- Limitaciones y seguridad del alpha
- Repositorio y releases en GitHub (denoland/celld)
- Precios oficiales de Cloudflare Durable Objects
- Litestream, origen del formato de réplica LTX
🧨 Última oprtunidad para recibir la dinamita que mereces sobre programación con IA el próximo domingo: Suscríbete gratis a Web Reactiva en https://webreactiva.com/newsletter
12 recursos para developers cada domingo en tu bandeja de entrada
Además de una skill práctica bien explicada, trucos para mejorar tu futuro profesional y una pizquita de humor útil para el resto de la semana. Gratis.