celld Deleted the Control Plane, So Your S3 Bucket Is Now the Whole Control Plane
Deno's new daemon runs Cloudflare Workers and Durable Objects on your own machines with no consensus service, no join server, and no account layer. Here's what that buys you and what it costs.
There is no membership protocol in celld. No failure detector, no consensus service, no join server, no account service, no placement controller. A node figures out which of its peers owns which object by reading a small record out of an S3 bucket and doing a compare-and-swap on it.
That's the whole coordination story. Everything distributed systems usually spend a year building, celld pushed into a feature that object storage already had.
Ryan Dahl and the Deno team shipped it this week, and it climbed the trending board fast enough that most of the writeups are still describing v0.0.1 while the project is on v0.1.0. The idea deserves the attention. The version churn deserves a paragraph of its own, and it gets one below.
What it is, in one paragraph you can act on
celld is a daemon that runs Cloudflare Workers and Durable Objects on machines you own. Every Durable Object is its own SQLite database, addressed by name, replicated continuously to an S3-compatible bucket you control. Each node embeds V8 and executes Wrangler bundles. The bucket holds deployments, cell state, and small ownership records, and it is the durable source of truth. Nodes are replaceable. When a cell moves or wakes, whichever node takes ownership restores that database from the bucket and resumes execution.
The JavaScript API is the Cloudflare Workers and Durable Objects API. That's the part that makes this real rather than aspirational. You are not porting to a lookalike. You are pointing existing code at a different runtime.
The position: this trades a control plane for a credential
The design is honest about its own tradeoff, and the README says it in one sentence: treat access to the bucket and its credentials as fleet administrator access.
Sit with that. In a normal cluster, the coordination layer is a service with its own authentication, its own authorization model, and its own audit log. celld deleted that service. The coordination substrate is now an object store, and object stores authenticate one way: with a credential that either can write to the bucket or can't.
Whoever holds those keys can rewrite ownership records, replace the current deployment, and read every cell's SQLite state. There is no second gate. The simplicity that makes celld pleasant to operate is the same property that collapses your entire administrative surface into one IAM policy.
I don't think that's a flaw. I think it's an exchange, and it's a good exchange for a fleet of ten nodes running one application. It's a bad exchange if you were planning to hand bucket credentials to a CI job that also runs untrusted code. The security and limitations pages exist for a reason and the README tells you to read them before operating a public fleet.
The parts that are better than I expected
Sharding is structural. Because every object is its own small database, applications shard by construction. The contention and blast-radius failures of one shared database are designed out rather than managed, which is a different claim from "we made the shared database faster."
Peer traffic is authenticated properly. The first current node writes fleet/peer-auth.json into the bucket, and every peer request after that is protocol-versioned, body-bound, HMAC-authenticated, clock-bounded, and replay-protected with that fleet secret. That's more care than most alpha projects show.
The install path is verifiable. The installer downloads a binary whose provenance you can check with gh attestation verify, keeps immutable releases under ~/.local/lib/celld/releases, and atomically switches a single current pointer. Rollback is the previous SHA. There's a guarded uninstaller too, which is a small courtesy that tells you something about the people who wrote it.
Idle cells hibernate to the bucket, where a cell is an object in S3 and costs close to nothing. Resident cells are in memory. That's the economic argument, and it holds up better than a per-container pricing model for workloads with a long tail of mostly-idle tenants.
Putting this into practice
Look before you install. The release image runs on Linux x86-64 and ARM64:
docker run --rm ghcr.io/denoland/celld --version
Then give it a scratch bucket with narrowly scoped credentials and nothing else in it. Deploy and run against the same bucket:
celld deploy . --bucket s3://my-cells-bucket
celld \
--bucket s3://my-cells-bucket \
--listen 0.0.0.0:8080 \
--advertise 10.0.0.12:8080
Drop --endpoint and --region for real AWS S3, add them for R2 or anything else S3-compatible. Worker projects need esbuild on PATH; asset-only projects don't.
Put every advertised address on a private network or an encrypted overlay before you go further. Peer HTTP does not terminate TLS. celld enforces this rather than warning about it: a literal public IP is rejected unless you pass --unsafe-public-advertise explicitly, and RFC 6598 overlay addresses like Tailscale's are accepted as of v0.0.2.
Use celld diagnose --bucket s3://my-cells-bucket early and often. It enumerates every node lease, does a signed direct probe of each live peer, keeps checking after individual failures, and distinguishes expired records from malformed advertise addresses from unreachable peers from incompatible protocols. It also prints per-node resident-cell, WebSocket, RSS, CPU, file-descriptor, pressure, and shedding samples. Most alpha software makes you guess at this.
Read docs/cloudflare-compat.md before you assume your Worker ports. KV, R2, wrangler.toml, and routes are out of scope. An unknown key or API causes a loud failure, and the docs state that a silent gap is a bug, which is the failure mode you want.
Honest limitations
The docs and the releases already disagree. The README on main says pressure shedding is opt-in while safe defaults are being measured, and documents CELLD_MAX_RESIDENT_CELLS alongside CELLD_RESIDENT_LOW_WATER. The limitations page says pressure shedding is off. The v0.1.0 release notes from August 5 say load shedding was rebuilt, the resident-cell limit is now a hard cap enforced at admission, RSS shedding is on by default at 80% of available memory, and CELLD_RESIDENT_LOW_WATER is now ignored. Three tagged releases landed between August 2 and August 5. Read the release notes as the source of truth and treat the README as a week behind.
The license moved. The v0.1.0 notes state celld is relicensed Apache-2.0. If you vendored anything from this repo on August 2, the terms you copied are not the terms on main today. Check what you took.
It's alpha and says so. A fleet runs one application deployment. No multi-tenant scheduler, no account service, no managed ingress, no global placement layer. Public tests cover the standalone engine smoke path, with conformance against Workers and Durable Objects reference behavior plus a deterministic fault-injection simulation running before each release rather than in the open.
Some rough edges will bite specific workloads. An outbound Durable Object WebSocket keeps its cell resident and does not survive the cell moving to a different node, so keep connection intent in storage and reconnect after activation. Cross-node WebSocket ingress works through the signed peer tunnel, but test coverage for close codes and reconnections across nodes is thinner than for a single node. If latency matters, route a cell's traffic to its owner. Credentials come from the AWS_* environment or explicit managed credentials including instance metadata and web identity tokens; celld does not read ~/.aws profiles or SSO logins. No Windows, and Intel Macs get no prebuilt binaries.
Momentum is not adoption. I watched the star count move from 227 to 291 across a single research session. Trending boards measure momentum, and momentum on a repo with a well-known author and eight forks tells you people are looking, not that anyone is running it in production.
Pull requests are disabled, with the stated reason being that coding agents make it too easy to send a large low-context change that costs maintainers more time than it saves. Patches go to Ryan by email as a git format-patch attachment, and emailing one assigns rights to Deno Land Inc. under the CLA in the README. If your plan involved upstreaming a fix quickly, adjust it.
What to do with this
If you have written against Durable Objects and disliked the lock-in, celld is worth an afternoon this week. The migration path is genuine, the operational surface is small enough to hold in your head, and the failure modes are documented rather than discovered.
If you're evaluating it for anything with real data behind it, the question to answer first is not about performance. It's about who holds the bucket credentials, what else those credentials can reach, and whether you're comfortable with one IAM policy standing in for an entire control plane. Answer that honestly and the rest of the decision gets easy.
Sources: denoland/celld, celld README, celld limitations, celld releases, celld.dev.