Introduction

Traditional web applications usually separate compute from state: application servers remain stateless, while data lives in MySQL, Redis, or a message queue. Once the product needs chat rooms, collaborative editing, multiplayer games, or AI agents, we also have to solve connection routing, concurrency control, sharding, and failure recovery.

Cloudflare Durable Objects offers a particularly interesting abstraction. Each object has a stable identity, a single-threaded execution environment, and private storage. A user, document, or chat room can live in its own object, keeping state close to the code that operates on it.

Durable Objects, however, have always been tied to Cloudflare’s infrastructure. celld attempts to bring the same programming model to servers and object storage that we control.

In the project’s own words:

Self-hosted, distributed Durable Objects.

What Is a Cell

In celld, a cell is the equivalent of a Durable Object: a small named server with its own SQLite database. It can handle HTTP requests, hold WebSocket connections, schedule alarms, and make outbound requests.

A Cell maps naturally to a business boundary such as:

  • a chat room or collaborative document;
  • a user, tenant, or device;
  • a multiplayer game room;
  • an AI agent with its own memory, inbox, and schedule.

Each Cell runs on one thread. Another request can interleave only when the current request awaits, while storage operations are synchronous and never interleave. Many problems that would otherwise require distributed locks or transaction coordination can therefore be handled inside the Cell.

A Cell does not need to stay in memory forever. It can move from Resident to Hibernated or Inactive. An inactive Cell exists only as data in object storage and is restored when the next request arrives. Large fleets of infrequently active agents, rooms, or tenants consequently do not consume compute resources continuously.

How celld Works

The foundation of celld can be summarized as:

celld = V8 + SQLite + LTX + Object Storage

Each machine running celld is a Node, and multiple Nodes sharing one Bucket form a Fleet. There is no separate membership service, failure detector, or consensus cluster. Instead, object storage acts as the coordinator.

Cell ownership is stored in the Bucket and claimed using conditional writes provided by the object store. Only one Node can own a Cell at a time. Ownership is a renewable lease; when a Node fails and stops renewing it, another Node can take over the Cell.

Each Cell stores its state in SQLite, then continuously replicates changes to the Bucket as LTX segments. With one Node, a write must first become durable in the Bucket. With two or more Nodes, the serving Node can replicate the write to another Node’s disk before uploading it to the Bucket asynchronously, reducing synchronous write latency.

The central guarantee is RPO=0: a write acknowledged as successful is not lost after a Node failure. That does not mean self-hosting is automatically more reliable. We still own the servers, network, Bucket, capacity planning, and monitoring. The difference is that the failure domain and operational evidence now live in infrastructure we can observe and control.

Cloudflare Workers Compatibility

celld reads an existing wrangler.json or wrangler.jsonc, so many Cloudflare Workers applications can be deployed without changing their code. Its main supported capabilities currently include:

  • Workers and Durable Objects;
  • KV, Queues, D1, and R2;
  • Workflows and Cron Triggers;
  • static assets and WebAssembly;
  • Service Bindings.

Durable Object Facets and Dynamic Workers remain experimental. Cloudflare-specific services such as Workers AI, Vectorize, Hyperdrive, Browser Rendering, Email Workers, and Python Workers are not supported.

One design choice I particularly like is that celld deploy rejects unknown Wrangler configuration keys instead of silently ignoring them. This prevents a deployment from appearing successful while a critical capability is actually missing.

Installation and Local Development

celld is distributed as a static executable and can be installed with the official script:

curl -fsSL https://celld.dev/install.sh | sh

You can also run the container image directly:

docker run --rm ghcr.io/denoland/celld --version

If you already have a Wrangler project, enter its directory and run:

celld dev

This starts a local object store, deploys the application, and runs one Node at http://127.0.0.1:9876 by default. It requires neither Docker nor a cloud Bucket.

Local state is stored in .celld/dev, so .celld/ should be added to .gitignore. To discard the previous state and start clean, run:

celld dev --clean

celld dev also watches source and configuration files. A failed build leaves the current version running; a successful build restarts the Node while retaining durable state. This makes the local feedback loop especially convenient for Durable Object development.

Deploying a Fleet

A production deployment first needs an S3-compatible store, Google Cloud Storage, or Azure Blob Storage. With S3, for example, deploy the Wrangler project into a Bucket:

export CELLD_BUCKET=s3://my-cells-bucket

celld deploy . --bucket "$CELLD_BUCKET"

Then start the first Node:

celld \
  --bucket "$CELLD_BUCKET" \
  --listen 0.0.0.0:8080 \
  --internal-listen 10.0.0.12:8081 \
  --advertise 10.0.0.12:8081

To add capacity, start another Node against the same Bucket and give it an internal address reachable by its peers. Nodes discover one another from leases in the Bucket, so there is no join command and no fixed membership list to maintain.

Port 8080 can sit behind a load balancer, but the internal listener must remain on a trusted private network. celld does not terminate TLS itself. The documentation recommends terminating TLS at an ingress proxy and protecting peer traffic with a private network or an encrypted overlay such as WireGuard or Tailscale.

Where It Fits

What makes celld interesting to me is not simply the ability to “run Cloudflare in your own data center.” It turns the Durable Objects stateful actor model into an infrastructure component that can be chosen independently.

celld is worth exploring when a system naturally shards by user, document, room, device, or agent and also needs WebSockets, durable state, and single-threaded consistency. It is also attractive for existing Workers projects, data-sovereignty requirements, explicit failure-domain control, or large numbers of low-activity Cells where cost matters.

It is not a direct replacement for a traditional database or Kubernetes. Cross-Cell queries and transactions become more involved, while production still needs load balancing, TLS, private networking, Bucket permissions, monitoring, and capacity management. Wrangler compatibility is not complete either, so the compatibility matrix and documented limitations should be reviewed before migrating an application.

Conclusion

Durable Objects reduce the questions of where state lives, which process handles a request, and how concurrency is controlled into one elegant programming model. celld takes the next step by separating that model from a single cloud platform.

It uses object storage for coordination and long-term state, SQLite for each Cell’s data, and LTX plus peer replication for durability and failover. The architecture does not remove the complexity of distributed systems, but it packages much of that complexity inside an observable, self-hosted runtime.

celld is still a young project, and its compatibility and production track record need time to mature. For real-time collaboration, multiplayer rooms, large AI agent fleets, and applications naturally sharded by tenant, however, it opens a genuinely interesting new path.

I hope this is helpful. Happy hacking…