denoland/celldPublic

self-hosted, distributed Durable Objects

AI summary: A self-hosted, distributed daemon for running Cloudflare Workers and Durable Objects backed by SQLite and S3 without a consensus plane.

Stars
5K
+75 today
Forks
207
Watchers
27
Open issues
35
Open PRs
0
Contributors
~2
Commits
12
Branches
1

RustApache-2.0Created Apr 25, 2025Last push 3d agoLatest release v0.6.1+188 stars this week+517 this month

Quick answers

What is celld?
A self-hosted, distributed daemon for running Cloudflare Workers and Durable Objects backed by SQLite and S3 without a consensus plane.
What does celld do?
Celld is an open-source daemon that embeds the V8 JavaScript engine to execute Wrangler bundles, enabling developers to self-host Cloudflare Workers and Durable Objects. Each Durable Object is isolated within its own dedicated SQLite database and is continuously replicated to a user-owned S3-compatible bucket. Instead of relying on complex control planes, membership protocols, or consensus services, the nodes coordinate entirely through object-storage compare-and-swap operations to guarantee exclusive ownership. This architecture shards applications by construction, eliminating the blast-radius failures typical of monolithic shared databases while allowing idle objects to hibernate securely.
Who is celld for?
Backend developers and infrastructure engineers looking for a self-hosted alternative to Cloudflare's serverless stateful computing model. It requires familiarity with Wrangler, V8 isolates, and S3-compatible storage.
How do I get started with celld?
curl -fsSL https://celld.dev/install.sh | sh
How popular is celld on GitHub?
denoland/celld has 4,998 stars and 207 forks on GitHub, and gained 188 stars in the last 7 days.
What license does celld use?
denoland/celld is released under the Apache-2.0 license.

Star history

since Aug 8, 2026
02K4KAug 2026Aug 2026Sep 2026Oct 2026
5K stars as of Oct 4, 2026. Measured daily since Aug 8, 2026; GitHub no longer exposes earlier star timestamps.

Update history

1 recorded
  • Oct 4, 2026New release v0.6.1 (previously v0.5.1).

Contribution activity

commits per day, last 52 weeks
OctNovDecJanFebMarAprMayJunJulAugSepOctMonWedFri2025-10-12: 0 commits2025-10-13: 0 commits2025-10-14: 0 commits2025-10-15: 0 commits2025-10-16: 0 commits2025-10-17: 0 commits2025-10-18: 0 commits2025-10-19: 0 commits2025-10-20: 0 commits2025-10-21: 0 commits2025-10-22: 0 commits2025-10-23: 0 commits2025-10-24: 0 commits2025-10-25: 0 commits2025-10-26: 0 commits2025-10-27: 0 commits2025-10-28: 0 commits2025-10-29: 0 commits2025-10-30: 0 commits2025-10-31: 0 commits2025-11-01: 0 commits2025-11-02: 0 commits2025-11-03: 0 commits2025-11-04: 0 commits2025-11-05: 0 commits2025-11-06: 0 commits2025-11-07: 0 commits2025-11-08: 0 commits2025-11-09: 0 commits2025-11-10: 0 commits2025-11-11: 0 commits2025-11-12: 0 commits2025-11-13: 0 commits2025-11-14: 0 commits2025-11-15: 0 commits2025-11-16: 0 commits2025-11-17: 0 commits2025-11-18: 0 commits2025-11-19: 0 commits2025-11-20: 0 commits2025-11-21: 0 commits2025-11-22: 0 commits2025-11-23: 0 commits2025-11-24: 0 commits2025-11-25: 0 commits2025-11-26: 0 commits2025-11-27: 0 commits2025-11-28: 0 commits2025-11-29: 0 commits2025-11-30: 0 commits2025-12-01: 0 commits2025-12-02: 0 commits2025-12-03: 0 commits2025-12-04: 0 commits2025-12-05: 0 commits2025-12-06: 0 commits2025-12-07: 0 commits2025-12-08: 0 commits2025-12-09: 0 commits2025-12-10: 0 commits2025-12-11: 0 commits2025-12-12: 0 commits2025-12-13: 0 commits2025-12-14: 0 commits2025-12-15: 0 commits2025-12-16: 0 commits2025-12-17: 0 commits2025-12-18: 0 commits2025-12-19: 0 commits2025-12-20: 0 commits2025-12-21: 0 commits2025-12-22: 0 commits2025-12-23: 0 commits2025-12-24: 0 commits2025-12-25: 0 commits2025-12-26: 0 commits2025-12-27: 0 commits2025-12-28: 0 commits2025-12-29: 0 commits2025-12-30: 0 commits2025-12-31: 0 commits2026-01-01: 0 commits2026-01-02: 0 commits2026-01-03: 0 commits2026-01-04: 0 commits2026-01-05: 0 commits2026-01-06: 0 commits2026-01-07: 0 commits2026-01-08: 0 commits2026-01-09: 0 commits2026-01-10: 0 commits2026-01-11: 0 commits2026-01-12: 0 commits2026-01-13: 0 commits2026-01-14: 0 commits2026-01-15: 0 commits2026-01-16: 0 commits2026-01-17: 0 commits2026-01-18: 0 commits2026-01-19: 0 commits2026-01-20: 0 commits2026-01-21: 0 commits2026-01-22: 0 commits2026-01-23: 0 commits2026-01-24: 0 commits2026-01-25: 0 commits2026-01-26: 0 commits2026-01-27: 0 commits2026-01-28: 0 commits2026-01-29: 0 commits2026-01-30: 0 commits2026-01-31: 0 commits2026-02-01: 0 commits2026-02-02: 0 commits2026-02-03: 0 commits2026-02-04: 0 commits2026-02-05: 0 commits2026-02-06: 0 commits2026-02-07: 0 commits2026-02-08: 0 commits2026-02-09: 0 commits2026-02-10: 0 commits2026-02-11: 0 commits2026-02-12: 0 commits2026-02-13: 0 commits2026-02-14: 0 commits2026-02-15: 0 commits2026-02-16: 0 commits2026-02-17: 0 commits2026-02-18: 0 commits2026-02-19: 0 commits2026-02-20: 0 commits2026-02-21: 0 commits2026-02-22: 0 commits2026-02-23: 0 commits2026-02-24: 0 commits2026-02-25: 0 commits2026-02-26: 0 commits2026-02-27: 0 commits2026-02-28: 0 commits2026-03-01: 0 commits2026-03-02: 0 commits2026-03-03: 0 commits2026-03-04: 0 commits2026-03-05: 0 commits2026-03-06: 0 commits2026-03-07: 0 commits2026-03-08: 0 commits2026-03-09: 0 commits2026-03-10: 0 commits2026-03-11: 0 commits2026-03-12: 0 commits2026-03-13: 0 commits2026-03-14: 0 commits2026-03-15: 0 commits2026-03-16: 0 commits2026-03-17: 0 commits2026-03-18: 0 commits2026-03-19: 0 commits2026-03-20: 0 commits2026-03-21: 0 commits2026-03-22: 0 commits2026-03-23: 0 commits2026-03-24: 0 commits2026-03-25: 0 commits2026-03-26: 0 commits2026-03-27: 0 commits2026-03-28: 0 commits2026-03-29: 0 commits2026-03-30: 0 commits2026-03-31: 0 commits2026-04-01: 0 commits2026-04-02: 0 commits2026-04-03: 0 commits2026-04-04: 0 commits2026-04-05: 0 commits2026-04-06: 0 commits2026-04-07: 0 commits2026-04-08: 0 commits2026-04-09: 0 commits2026-04-10: 0 commits2026-04-11: 0 commits2026-04-12: 0 commits2026-04-13: 0 commits2026-04-14: 0 commits2026-04-15: 0 commits2026-04-16: 0 commits2026-04-17: 0 commits2026-04-18: 0 commits2026-04-19: 0 commits2026-04-20: 0 commits2026-04-21: 0 commits2026-04-22: 0 commits2026-04-23: 0 commits2026-04-24: 0 commits2026-04-25: 0 commits2026-04-26: 0 commits2026-04-27: 0 commits2026-04-28: 0 commits2026-04-29: 0 commits2026-04-30: 0 commits2026-05-01: 0 commits2026-05-02: 0 commits2026-05-03: 0 commits2026-05-04: 0 commits2026-05-05: 0 commits2026-05-06: 0 commits2026-05-07: 0 commits2026-05-08: 0 commits2026-05-09: 0 commits2026-05-10: 0 commits2026-05-11: 0 commits2026-05-12: 0 commits2026-05-13: 0 commits2026-05-14: 0 commits2026-05-15: 0 commits2026-05-16: 0 commits2026-05-17: 0 commits2026-05-18: 0 commits2026-05-19: 0 commits2026-05-20: 0 commits2026-05-21: 0 commits2026-05-22: 0 commits2026-05-23: 0 commits2026-05-24: 0 commits2026-05-25: 0 commits2026-05-26: 0 commits2026-05-27: 0 commits2026-05-28: 0 commits2026-05-29: 0 commits2026-05-30: 0 commits2026-05-31: 0 commits2026-06-01: 0 commits2026-06-02: 0 commits2026-06-03: 0 commits2026-06-04: 0 commits2026-06-05: 0 commits2026-06-06: 0 commits2026-06-07: 0 commits2026-06-08: 0 commits2026-06-09: 0 commits2026-06-10: 0 commits2026-06-11: 0 commits2026-06-12: 0 commits2026-06-13: 0 commits2026-06-14: 0 commits2026-06-15: 0 commits2026-06-16: 0 commits2026-06-17: 0 commits2026-06-18: 0 commits2026-06-19: 0 commits2026-06-20: 0 commits2026-06-21: 0 commits2026-06-22: 0 commits2026-06-23: 0 commits2026-06-24: 0 commits2026-06-25: 0 commits2026-06-26: 0 commits2026-06-27: 0 commits2026-06-28: 0 commits2026-06-29: 0 commits2026-06-30: 0 commits2026-07-01: 0 commits2026-07-02: 0 commits2026-07-03: 0 commits2026-07-04: 0 commits2026-07-05: 0 commits2026-07-06: 0 commits2026-07-07: 0 commits2026-07-08: 0 commits2026-07-09: 0 commits2026-07-10: 0 commits2026-07-11: 0 commits2026-07-12: 0 commits2026-07-13: 0 commits2026-07-14: 0 commits2026-07-15: 0 commits2026-07-16: 0 commits2026-07-17: 0 commits2026-07-18: 0 commits2026-07-19: 0 commits2026-07-20: 0 commits2026-07-21: 0 commits2026-07-22: 0 commits2026-07-23: 0 commits2026-07-24: 0 commits2026-07-25: 0 commits2026-07-26: 0 commits2026-07-27: 0 commits2026-07-28: 0 commits2026-07-29: 0 commits2026-07-30: 0 commits2026-07-31: 0 commits2026-08-01: 0 commits2026-08-02: 1 commit2026-08-03: 0 commits2026-08-04: 1 commit2026-08-05: 1 commit2026-08-06: 0 commits2026-08-07: 0 commits2026-08-08: 0 commits2026-08-09: 0 commits2026-08-10: 0 commits2026-08-11: 0 commits2026-08-12: 1 commit2026-08-13: 0 commits2026-08-14: 1 commit2026-08-15: 0 commits2026-08-16: 0 commits2026-08-17: 0 commits2026-08-18: 0 commits2026-08-19: 0 commits2026-08-20: 1 commit2026-08-21: 0 commits2026-08-22: 0 commits2026-08-23: 0 commits2026-08-24: 0 commits2026-08-25: 0 commits2026-08-26: 0 commits2026-08-27: 0 commits2026-08-28: 1 commit2026-08-29: 0 commits2026-08-30: 0 commits2026-08-31: 0 commits2026-09-01: 0 commits2026-09-02: 0 commits2026-09-03: 0 commits2026-09-04: 0 commits2026-09-05: 1 commit2026-09-06: 0 commits2026-09-07: 0 commits2026-09-08: 0 commits2026-09-09: 0 commits2026-09-10: 0 commits2026-09-11: 0 commits2026-09-12: 0 commits2026-09-13: 0 commits2026-09-14: 1 commit2026-09-15: 0 commits2026-09-16: 0 commits2026-09-17: 0 commits2026-09-18: 0 commits2026-09-19: 1 commit2026-09-20: 0 commits2026-09-21: 0 commits2026-09-22: 0 commits2026-09-23: 0 commits2026-09-24: 0 commits2026-09-25: 0 commits2026-09-26: 1 commit2026-09-27: 0 commits2026-09-28: 0 commits2026-09-29: 0 commits2026-09-30: 0 commits2026-10-01: 1 commit2026-10-02: 0 commits2026-10-03: 0 commits2026-10-04: 0 commits2026-10-05: 0 commits2026-10-06: 0 commits2026-10-07: 0 commits2026-10-08: 0 commits2026-10-09: 0 commits2026-10-10: 0 commits
12 commits in the last yearLessMore

Signals and awards

derived from tracked data
  • Permissive license

    Apache-2.0

  • Continuous integration

    Automated checks passing

  • Repeat trending

    8 trending appearances

What celld does

Celld is an open-source daemon that embeds the V8 JavaScript engine to execute Wrangler bundles, enabling developers to self-host Cloudflare Workers and Durable Objects. Each Durable Object is isolated within its own dedicated SQLite database and is continuously replicated to a user-owned S3-compatible bucket. Instead of relying on complex control planes, membership protocols, or consensus services, the nodes coordinate entirely through object-storage compare-and-swap operations to guarantee exclusive ownership. This architecture shards applications by construction, eliminating the blast-radius failures typical of monolithic shared databases while allowing idle objects to hibernate securely.

Backend developers and infrastructure engineers looking for a self-hosted alternative to Cloudflare's serverless stateful computing model. It requires familiarity with Wrangler, V8 isolates, and S3-compatible storage.

  • Native V8 Execution: Embeds the V8 engine to execute Cloudflare Worker scripts and Wrangler bundles locally.
  • Isolated State Sharding: Assigns each Durable Object its own dedicated SQLite database to eliminate shared contention.
  • Consensus-Free Coordination: Uses S3-compatible object storage compare-and-swap to enforce exactly-one ownership across the fleet.
  • Continuous Remote Replication: Streams object states directly to S3 buckets, ensuring the storage layer acts as the durable source of truth.
  • Efficient Hibernation: Automatically spins down idle cells to drastically reduce idle compute footprint.

Where teams use it

Self-Hosted Edge Computing

Infrastructure teams can deploy edge-like serverless compute locally without relying on external cloud providers.

Stateful Actor Systems

Game backends or collaborative apps can use Durable Objects to maintain isolated state per room or document.

Disaster Resilient Sharding

Deployments can scale horizontally by adding nodes since data ownership naturally shifts via bucket coordination.

Edge Migration Testing

Developers can test complex Cloudflare Workers architectures in CI/CD environments matching production behavior.

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

README

main branch

celld

Self-hosted, distributed Durable Objects.

celld is an open-source daemon that runs a Cloudflare Workers application on your own machines: Workers, Durable Objects, KV, Queues, D1, R2, Workflows, Cron Triggers, and static assets, deployed from the wrangler.json that you already have. Each object is a cell: a named server with its own SQLite database. celld stores the long-term state in your S3-compatible, Google Cloud Storage, or Azure Blob Storage bucket. It needs no serving control plane or consensus service. An inactive cell costs almost nothing. Learn more at celld.dev or read the documentation.

How it works

A node is one celld process, and you run one on each machine. Every node embeds V8 and executes Wrangler bundles. The nodes that share one bucket are a fleet, and that bucket holds the deployments, the cell state, and small ownership records. A conditional bucket write gives a node the ownership of a cell, so exactly one node owns a cell at a time. The fleet needs no membership protocol, failure detector, or consensus service. Signed peer HTTP provides routing and replicated-log transport.

celld captures each committed SQLite write in the LTX replication format. A single node proves the write durable by uploading that data to the bucket. A fleet of two or more nodes proves it sooner: the owner sends the data to one or two other nodes, and the write is durable as soon as they hold it on their disks. celld uploads the data to the bucket afterwards. A single node has no other node to send to, so each write waits for the bucket, and those writes are much slower. Before a takeover restores a cell, celld recovers an open log from the prior owner, so the bucket holds the long-term state and nodes stay replaceable. See what celld guarantees for the complete protocol.

What runs on celld

celld runs the programmatic Workers platform: the runtime, and each binding that Cloudflare builds on Workers and Durable Objects. A KV namespace, a queue, a D1 database, and a Workflow are each a cell, so they get the same lease, the same replication, and the same failover as a Durable Object. R2 bindings read, write, and list objects directly in the fleet bucket. Each row links to a project that deploys as-is:

service example
Workers: fetch handlers, service bindings, JS RPC, Node.js compat hello
Durable Objects: SQLite storage, alarms, hibernating WebSockets counter
KV: list, metadata, expiration, bulk import kv
Queues: producers, batching consumers, retries, dead letters queues
D1: SQL databases, batches, migrations d1
R2: reads, writes, lists, multipart uploads r2
Workflows: durable steps, sleeps, events, pause and restart workflow
Cron Triggers: one run for each occurrence across the fleet cron
Static assets: asset-only or with a Worker, _headers, _redirects static-assets
Dynamic Workers: runtime-loaded code and Tail Worker observability dynamic-worker-tails
Containers (experimental): a Durable Object that supervises a container, @cloudflare/containers container
Sandboxes: the Cloudflare Sandbox SDK, @cloudflare/sandbox, on a container per sandbox sandbox

A product that needs the Cloudflare network, a GPU, or a browser farm is out of scope. The Cloudflare compatibility page lists each gap in the services above.

Install

The installer downloads the celld binary (provenance is verifiable with gh attestation verify):

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

Put ~/.local/bin on your PATH if the installer asks you to.

Worker projects deployed with celld deploy need esbuild on PATH; asset-only projects do not.

The installer keeps each release under ~/.local/lib/celld/releases and points one symlink at the current one. To remove celld, delete the symlink and the releases:

rm `which celld` && rm -rf ~/.local/lib/celld

Container

The release image contains the celld binary and is published for Linux x86-64 and ARM64:

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

Persist the runtime's local state and pass the standard AWS credential environment through:

docker volume create celld-state
docker run --rm --network host \
  -e AWS_ACCESS_KEY_ID \
  -e AWS_SECRET_ACCESS_KEY \
  -e AWS_SESSION_TOKEN \
  -e CELLD_WATCH=/var/lib/celld/state \
  -v celld-state:/var/lib/celld \
  ghcr.io/denoland/celld \
  --bucket s3://my-cells-bucket \
  --endpoint https://ACCOUNT.r2.cloudflarestorage.com \
  --region auto \
  --listen 0.0.0.0:8080 \
  --internal-listen 10.0.0.12:8081 \
  --advertise node-a.internal:8081

Drop --endpoint and --region for AWS S3. Expose port 8080 through the load balancer, and keep port 8081 on the private network.

Run it

Run an application locally without a cloud bucket:

celld dev

The command starts one celld node with a local object store, so it needs no Docker or cloud bucket. The Worker listener uses http://127.0.0.1:9876. Use celld dev --port PORT to select a different Worker port. Use celld dev --host IP to select a different interface. A non-loopback IP exposes the Worker listener to the network, and the internal operator listener stays on loopback. The command keeps the application state in .celld/dev, so a later invocation uses the same durable data.

The state also survives a configuration change, and celld does not migrate it, so an object can keep a value that the new configuration rejects. The failure then looks unrelated to the change. Use celld dev --clean to delete .celld/dev before the server starts and run from an empty local state.

The default display highlights the application URL and hides the node warning and information logs. Use celld dev --logs to show these logs. The errors remain visible without this flag. Set NO_COLOR to disable color, or set FORCE_COLOR to enable color when the output is not a terminal. NO_COLOR always takes priority.

The command watches the project and rebuilds the application after a source or configuration change. It keeps the current application running if a build fails, and a successful restart retains the durable state. See the documentation for the complete local-development contract.

celld uses the standard AWS credential chain. On Amazon EKS, celld reads the Pod Identity credentials from the injected environment variables and the authorization-token file. Deploy to an S3-compatible bucket, then start celld against the same bucket:

celld deploy . \
  --bucket s3://my-cells-bucket

celld \
  --bucket s3://my-cells-bucket \
  --listen 0.0.0.0:8080 \
  --internal-listen 10.0.0.12:8081 \
  --advertise 10.0.0.12:8081

One node proves each write through the bucket, so a write costs one storage round trip. Start a second node against the same bucket, and celld sends each write to it: the write then finishes as soon as the second node holds the data on its disk, which is much faster than the round trip.

Run two or more nodes if write latency matters to you. The second node needs no extra configuration, because a node finds the other nodes through the bucket.

How much faster depends on how far your bucket is and how loaded the fleet is. A write to a region-local store takes about 90 ms. One loaded lab fleet measured about 600 ms against a store that was not region-local, and about 25 ms once a second node held the write. See what celld guarantees.

Use --endpoint for another S3-compatible service and --region when it cannot be inferred. A gs:// bucket selects Google Cloud Storage: celld then uses the Cloud Storage XML API with generation preconditions and authenticates with Application Default Credentials. celld rejects an S3 --endpoint for a gs:// bucket, and it ignores the storage region:

celld deploy . --bucket gs://my-cells-bucket
celld --bucket gs://my-cells-bucket --listen 0.0.0.0:8080 \
  --internal-listen 10.0.0.12:8081 --advertise 10.0.0.12:8081

An az:// bucket selects Azure Blob Storage, where the NAME is the container and AZURE_STORAGE_ACCOUNT_NAME names the storage account. celld requires exactly one credential family: a storage account key, a managed identity, or a workload identity. An AKS workload identity uses AZURE_AUTHORITY_HOST, AZURE_CLIENT_ID, AZURE_TENANT_ID, and AZURE_FEDERATED_TOKEN_FILE, and the authority host must identify the public Azure cloud. A Microsoft Entra identity needs data-plane permission to read, write, list, and delete blobs; the Storage Blob Data Contributor role supplies these. celld rejects an S3 --endpoint for an az:// bucket, and it ignores the storage region. See what celld guarantees for the qualification:

export AZURE_STORAGE_ACCOUNT_NAME=myaccount
celld deploy . --bucket az://my-cells-container
celld --bucket az://my-cells-container --listen 0.0.0.0:8080 \
  --internal-listen 10.0.0.12:8081 --advertise 10.0.0.12:8081

A fleet runs one application, and every node loads its latest successfully committed deployment from deploy/current.json. celld deploy invokes esbuild from PATH for Worker code, accepts the supported Wrangler config subset (including co-deployed or asset-only static assets), and writes the deployment objects directly, using the documented types in crates/celld/protocol.rs. Every node discovers owners and peers from bucket leases; there is no account or join service. Run celld --help for the complete command line.

An upgrade from v0.4.1 preserves the existing bucket and node data directories. Stop all old nodes, then start the new binaries with the same configuration. Startup upgrades the wake format automatically before a node serves traffic. Mixed versions cannot share a serving fleet. The wake format contract describes the startup checks and the boundary for existing fleet data.

Peer HTTP and the operator API use the internal listener. Put every advertised address on a trusted private network or an encrypted overlay such as WireGuard or Tailscale, and do not publish the internal port. celld rejects a literal public IP unless you supply --unsafe-public-advertise. An explicit advertised address requires an explicit internal-listener address, and you must route the advertised address to the internal listener, because celld cannot verify a hostname or a translated port. The first current node creates fleet/peer-auth.json in the bucket. Cell fetch and RPC requests carry a protocol version and depend on the trusted private network. Peer-control and reserved-cell operator requests use the fleet HMAC. This HMAC binds each body and supplies a clock limit and replay protection. Treat access to the bucket and its credentials as fleet administrator access.

Operate a fleet

celld diagnose enumerates every node lease by default, then performs a signed direct probe of each live peer:

celld diagnose --bucket s3://my-cells-bucket

The report keeps checking after an individual failure and distinguishes expired records, malformed or unsafe advertise addresses, unreachable peers, and incompatible protocols. It also prints each node's coarse owned-cell, resident-cell, WebSocket, RSS, CPU, file-descriptor, pressure, and shedding sample. Pass one or more --peer NODE_ID options to restrict the check.

celld cell list lists the Durable Object instances in the fleet bucket:

celld cell list --bucket s3://my-cells-bucket

The command prints one Class:ID cell scope per line. Give a class name to list only the instances of that class, and pass --json for one JSON object per line. An instance appears after the first event reaches it, because its owner then writes an ownership record to the bucket. An ID that an application only derives does not appear.

The listing is bounded. One storage request returns at most 1000 instances, so the command prints at most 1000 and reports on stderr that more exist. Pass --after SCOPE to continue from the last instance printed, or --all to read the whole listing.

celld d1 runs SQL and migrations against a deployed D1 database. It finds a node through the same node leases, and that node sends the work to the node that owns the database:

celld d1 migrations apply ledger --bucket s3://my-cells-bucket

The migration file extension is ASCII case-insensitive, so .sql and .SQL files are migrations. The command ignores a file with a different extension.

celld kv reads and writes a deployed KV namespace. Its bulk commands use the Wrangler file format, so a Wrangler export can migrate directly into celld:

celld kv bulk put sessions wrangler-export.json \
  --bucket s3://my-cells-bucket

celld r2 reads and writes the objects behind an r2_buckets binding. The command reads the fleet bucket directly, so it needs no running node and a release pipeline can publish an artifact before it deploys the Worker:

celld r2 put assets app.zip --path dist/app.zip \
  --content-type application/zip \
  --metadata '{"release":"1.2.3"}' \
  --bucket s3://my-cells-bucket

celld queue inspects and controls a deployed Queue. A queue can continue to accept messages while delivery is paused:

celld queue info jobs --bucket s3://my-cells-bucket
celld queue pause jobs --bucket s3://my-cells-bucket
celld queue resume jobs --bucket s3://my-cells-bucket

Set a hard resident-cell limit on each loaded node:

CELLD_MAX_RESIDENT_CELLS=1000 \
celld --bucket s3://my-cells-bucket --listen 0.0.0.0:8080 \
  --internal-listen 10.0.0.12:8081 --advertise node-a.internal:8081

celld balances ownership across the fleet. Every node reads a shared fleet sample every five seconds. One node refreshes the sample from the node leases, so each refresh reads each lease once for the fleet. The node with the most owned cells per unit of weight hands at most 32 hibernated cells per sample to the peer that is furthest below its share. A hibernated cell moves as one record write, and its parked hibernatable WebSockets close with code 1012 so the clients reconnect to the new owner. A resident cell moves only after idle eviction hibernates it (CELLD_IDLE_EVICT_S). Set CELLD_PLACEMENT_WEIGHT to give a node a larger or a smaller share than its CPU count, and set CELLD_REBALANCE_INTERVAL_MS=0 to disable balancing. POST /rebalance/pause on the internal listener of any node pauses the fleet.

celld enables a memory-pressure threshold at 80% of the available memory by default. Set CELLD_MAX_RSS_MB to change the threshold, or set it to 0 to disable memory-pressure shedding. In a Linux cgroup, the threshold uses the greater of the allocator-adjusted RSS and the active cgroup working set. celld calculates the working set as memory.current less inactive_file from memory.stat, then it removes the measured allocator slack. This calculation includes active kernel charges that process RSS does not report, and it excludes file pages and allocator pages that celld cannot return by shedding a cell. Before each sample, celld returns the memory that the C allocator keeps after a cell stops, so a hibernated cell does not hold its storage cache in RSS. The /state route reports all four input measurements.

A separate absolute cap applies to the complete cgroup charge at 95% of the available memory. celld uses the process RSS when it cannot read a cgroup charge. The cap protects the node when shedding cannot return a kernel charge. The node logs a warning when the cap applies. The cap is a share of the available memory, not a share of the threshold. Therefore, a CELLD_MAX_RSS_MB value at or above 95% makes the cap the effective limit, and celld reports the decision at startup. CELLD_MAX_RSS_MB=0 disables the threshold and the cap together. When celld cannot read the size of the available memory, it applies a cap of 125% of an explicit threshold.

Under pressure, celld durably replicates and fences the least-recently used idle cells, publishes them as unowned without resetting their epochs, and refuses to reacquire new unowned cells. It does not shed a cell with active work or a live host WebSocket. A spare node receives no assignment; it acquires a released cell through the same bucket protocol when normal traffic reaches it. Each limit releases separately. The threshold releases at 80% of its value, and the cap releases at 80% of its value. Therefore, a crossing of one limit does not hold the node against the other.

Each isolate also has a V8 heap limit, separate from the memory of the node. The default is 128 MB, and it matches the limit of a Durable Object on Cloudflare; set CELLD_V8_HEAP_LIMIT_MB to change it. Each hibernatable WebSocket client holds state in the heap, so the limit decides how many clients a cell can carry: approximately 50,000 at the default, and approximately 512 MB for 100,000.

An isolate above 90% of this limit refuses a new hibernatable WebSocket, and it accepts again when the use of the heap falls under 90%. An isolate that reaches the limit also stops the materialization of a SQL result set; both errors name the heap. celld measures the heap before each event, and the isolate serves again when the use falls under 75% of the limit. An idle isolate holds a dead heap until something allocates, so celld forces a collection when a measurement is above that share. A restart of the process is not necessary.

Contributions

Pull requests are disabled. Coding agents make it too easy to send a large, low-context change that costs maintainers more time than it saves. Thoughtful contributions are welcome; please understand the code, keep the patch focused, and respect the review time you are asking for.

Send a git format-patch attachment to [email protected].

Contributor License Agreement: By emailing a patch, you certify that you have the right to submit it and assign to Deno Land Inc. all rights in the patch that you can assign. Where a right cannot be assigned, you grant Deno Land Inc. a perpetual, irrevocable, worldwide, royalty-free, transferable, sublicensable license to use, modify, combine, relicense, redistribute, or publish the patch, in whole or in part, with or without attribution.

License

Apache-2.0

See the limitations and security pages before operating a public fleet.

View on GitHub

Recent activity

commits and pull requests
  • v0.6.1

    bartlomieju committed f2bf648 · 3d ago

  • v0.6.0

    bartlomieju committed bad4649 · 8d ago

  • v0.5.1

    bartlomieju committed 42269c1 · 15d ago

  • v0.5.0

    ry committed 12d5b63 · 19d ago

  • v0.4.1

    ry committed 10cb130 · 29d ago

  • v0.4.0

    ry committed a52f990 · 1mo ago

  • v0.3.0

    ry committed 89e4ffc · 1mo ago

  • v0.2.1

    ry committed ae8fac0 · 1mo ago

  • v0.2.0

    ry committed 3f22aed · 1mo ago

  • v0.1.0

    ry committed 553ae73 · 2mo ago

Releases and announcements

12 total
  1. v0.6.1v0.6.1Oct 1, 20261.4K downloads

    Upgrading from v0.6.0 can use a rolling update. Setting `CELLD_LTX_RETENTION_SECS`, deploying a Python Worker, or raising `CELLD_MAX_ASSET_FILE_BYTES` above 25 MiB can be done only after every node runs v0.6.1. - Add support for Python Workers. - Bucket usage can now track a cell's data instead of growing with every activation: set `CELLD_LTX_RETENTION_SECS` to delete epochs that no restore reads. It is off by default. - New `celld cell gc --dry-run` lists the superseded epoch prefixes that epoch GC can delete, with their sizes, and writes nothing. - New `CELLD_MAX_ASSET_FILE_BYTES` (default 25 MiB) and `CELLD_MAX_DYNAMIC_WORKER_CODE_BYTES` (default 64 MiB) make the per-file asset limit and the Dynamic Worker module size limit configurable. - Console log records now carry the OpenTelemetry severity (`DEBUG`, `INFO`, `WARN`, `ERROR`) in the OTLP export and as Parquet columns. - WebSocket message handlers on one socket now start in arrival order and do not wait for the previous handler to finish. Hibernatable sockets keep send order across WebSocket handlers and RPC methods. - A loaded Worker is now released once no stub, entrypoint, class or running facet refers to it, and a later

  2. v0.6.0v0.6.0Sep 26, 20262.5K downloads

    Upgrading from v0.5.1 with fleet durability requires stopping the whole fleet first. A fleet with bucket durability can use a rolling update. - Each Durable Object facet has its own SQLite file and replication stream. A facet write no longer copies the facet database into the root or joins a root transaction. A facet can start from a class in `ctx.exports`. Facets from v0.5.1 migrate on first open. - `crypto.subtle` supports Ed25519 (also as `NODE-ED25519`) and X25519, with `raw` import and export. (#221) - Per-cell memory: the SQL statement cache is capped at 128 KiB of compiled statements instead of 1 MiB of SQL text, which could hold tens of MB. A cell shares one object store client instead of three, and operation timers no longer leak one map entry per operation. - Stricter workerd parity: `WorkerCode` requires `compatibilityDate`, a wasm module in `modules` must be `{ wasm: bytes }`, `export const X = "..."` in a main module fails the Worker's start, and the `transactionSync()` callback receives no argument. - `ctx.exports` holds `default` and each entrypoint, and `fetch()` on its stubs sends an HTTP request. - R2 keeps empty key segments, so `a/b`, `/a/b`, `a//b`, and `a/b/`

  3. v0.5.1v0.5.1Sep 19, 202640.9K downloads

    Upgrading from v0.5.0 can use a rolling update. Stop one node, wait for its replacement to report healthy, then continue to the next node. Highlights: - Dynamic Workers can enforce CPU time and subrequest limits from `WorkerCode.limits` or a `getEntrypoint()` call. - Dynamic Workers can send Tail Workers an invocation report with the request, response, console logs, exception, and outcome. - The new `celld r2` CLI tool can put, get, list, inspect, and delete objects behind an `r2_buckets` binding without a running node. It preserves the binding's object metadata. - `celld deploy` accepts Wrangler `define` values and `rules` for Text, Data, and CompiledWasm modules when it bundles a Worker. - KV accepts a `ReadableStream` value in `put()`. It checks the value-size limit while reading the stream. - The node caps its LTX writer and read-lock SQLite page caches, and returns freed C allocator pages before it measures memory pressure. - Compaction can read retained LTX bundles after their segments leave the in-memory index, so a slow cell can continue draining its history. - The `/evict/<cell>` operator route reports a refusal, cancellation, or failure instead of returning success befo

  4. v0.5.0v0.5.0Sep 15, 20264.4K downloads

    Upgrading from v0.4.1 requires stopping the whole fleet first. Highlights: - Support for Containers and the Cloudflare Sandbox SDK. - Support for worker_loaders in wrangler.json. Loaded Workers can receive service bindings and use a custom outbound fetch handler. - Service bindings now support fetch() on named entrypoints across Workers. - RPC support for default service bindings and nested properties. AbortSignal can pass through RPC calls on the same node. - Choose how long to keep completed Workflow runs, or delete them manually. - Support for .dev.vars in celld dev, with automatic reloads. - Support for WASM files in prebuilt deployments. - Lower memory use per cell and faster KV prefix listings. - Fixes for nested transactions, facet rollback, and unfinished SQL writes. - More reliable alarm delivery and background work after a response. - Database recovery fixes, with lower memory use during recovery and compaction. - Internal host functions are no longer exposed to application code. - Configure telemetry with CELLD_OTEL: 1 for the bucket, or an OTLP collector URL. Issues fixed: - #177: Pass service bindings to loaded Workers. - #192: Isolate host state between loaded Wor

  5. v0.4.1v0.4.1Sep 5, 20263.9K downloads

    You can do a rolling upgrade from v0.4.0. Highlights: - **Balance cell ownership across the fleet.** A node that joins takes hibernated cells from the nodes that hold the most, so it carries its share within minutes instead of waiting for new traffic. The fleet evens out again after a node leaves. One node samples the leases for the whole fleet, so the cost does not grow with the square of the fleet. - **Restore a large cell page by page.** The cell reads each page from the object store on first use, so it serves requests before the download completes. A large cell also hands off through its LTX chain instead of a whole-database snapshot. - **Queue throughput improves by an order of magnitude.** Producer calls share transactions and durability rounds, and each message gets a time-ordered id. One Queue sustained 7,357 sends per second over a 300,000-send soak with exact delivery, up from a few hundred. - **Fewer false durability timeouts under load.** The budget measures a stall: a queued write waits while the node keeps landing proofs. A follower commits a burst of frames as one fsync chain, and CRC64 verification uses SIMD. - **Alarms scale to the due work.** The waker lists one

Code frequency

additions and deletions
+131.4K-131.4KWeek of 2026-08-02: +131,415 linesWeek of 2026-08-02: -56,883 linesWeek of 2026-08-09: +26,477 linesWeek of 2026-08-09: -14,784 linesWeek of 2026-08-16: +18,769 linesWeek of 2026-08-16: -5,389 linesWeek of 2026-08-23: +36,543 linesWeek of 2026-08-23: -15,107 linesWeek of 2026-08-30: +36,026 linesWeek of 2026-08-30: -3,577 linesWeek of 2026-09-06: +0 linesWeek of 2026-09-06: -0 linesWeek of 2026-09-13: +21,008 linesWeek of 2026-09-13: -17,521 linesWeek of 2026-09-20: +11,174 linesWeek of 2026-09-20: -8,787 linesWeek of 2026-09-27: +4,677 linesWeek of 2026-09-27: -1,042 linesWeek of 2026-10-04: +0 linesWeek of 2026-10-04: -0 linesAug 2, 2026Oct 4, 2026
+286.1K lines added, -123.1K removed over the last year.

Commits per week

last 52 weeks
30Week of 2025-10-12: 0 commitsWeek of 2025-10-19: 0 commitsWeek of 2025-10-26: 0 commitsWeek of 2025-11-02: 0 commitsWeek of 2025-11-09: 0 commitsWeek of 2025-11-16: 0 commitsWeek of 2025-11-23: 0 commitsWeek of 2025-11-30: 0 commitsWeek of 2025-12-07: 0 commitsWeek of 2025-12-14: 0 commitsWeek of 2025-12-21: 0 commitsWeek of 2025-12-28: 0 commitsWeek of 2026-01-04: 0 commitsWeek of 2026-01-11: 0 commitsWeek of 2026-01-18: 0 commitsWeek of 2026-01-25: 0 commitsWeek of 2026-02-01: 0 commitsWeek of 2026-02-08: 0 commitsWeek of 2026-02-15: 0 commitsWeek of 2026-02-22: 0 commitsWeek of 2026-03-01: 0 commitsWeek of 2026-03-08: 0 commitsWeek of 2026-03-15: 0 commitsWeek of 2026-03-22: 0 commitsWeek of 2026-03-29: 0 commitsWeek of 2026-04-05: 0 commitsWeek of 2026-04-12: 0 commitsWeek of 2026-04-19: 0 commitsWeek of 2026-04-26: 0 commitsWeek of 2026-05-03: 0 commitsWeek of 2026-05-10: 0 commitsWeek of 2026-05-17: 0 commitsWeek of 2026-05-24: 0 commitsWeek of 2026-05-31: 0 commitsWeek of 2026-06-07: 0 commitsWeek of 2026-06-14: 0 commitsWeek of 2026-06-21: 0 commitsWeek of 2026-06-28: 0 commitsWeek of 2026-07-05: 0 commitsWeek of 2026-07-12: 0 commitsWeek of 2026-07-19: 0 commitsWeek of 2026-07-26: 0 commitsWeek of 2026-08-02: 3 commitsWeek of 2026-08-09: 2 commitsWeek of 2026-08-16: 1 commitsWeek of 2026-08-23: 1 commitsWeek of 2026-08-30: 1 commitsWeek of 2026-09-06: 0 commitsWeek of 2026-09-13: 2 commitsWeek of 2026-09-20: 1 commitsWeek of 2026-09-27: 1 commitsWeek of 2026-10-04: 0 commitsOct 12, 2025Oct 4, 2026
12 commits in the last 52 weeks.

When work happens

weekday and hour
SunMonTueWedThuFriSat036912151821Sun 0:00 — 0 commitsSun 1:00 — 0 commitsSun 2:00 — 0 commitsSun 3:00 — 0 commitsSun 4:00 — 0 commitsSun 5:00 — 0 commitsSun 6:00 — 0 commitsSun 7:00 — 0 commitsSun 8:00 — 0 commitsSun 9:00 — 0 commitsSun 10:00 — 0 commitsSun 11:00 — 0 commitsSun 12:00 — 1 commitsSun 13:00 — 0 commitsSun 14:00 — 0 commitsSun 15:00 — 0 commitsSun 16:00 — 0 commitsSun 17:00 — 0 commitsSun 18:00 — 0 commitsSun 19:00 — 0 commitsSun 20:00 — 0 commitsSun 21:00 — 0 commitsSun 22:00 — 0 commitsSun 23:00 — 0 commitsMon 0:00 — 0 commitsMon 1:00 — 0 commitsMon 2:00 — 0 commitsMon 3:00 — 0 commitsMon 4:00 — 0 commitsMon 5:00 — 0 commitsMon 6:00 — 0 commitsMon 7:00 — 0 commitsMon 8:00 — 0 commitsMon 9:00 — 0 commitsMon 10:00 — 0 commitsMon 11:00 — 0 commitsMon 12:00 — 0 commitsMon 13:00 — 0 commitsMon 14:00 — 0 commitsMon 15:00 — 0 commitsMon 16:00 — 0 commitsMon 17:00 — 0 commitsMon 18:00 — 0 commitsMon 19:00 — 0 commitsMon 20:00 — 0 commitsMon 21:00 — 1 commitsMon 22:00 — 0 commitsMon 23:00 — 0 commitsTue 0:00 — 0 commitsTue 1:00 — 0 commitsTue 2:00 — 0 commitsTue 3:00 — 0 commitsTue 4:00 — 0 commitsTue 5:00 — 0 commitsTue 6:00 — 0 commitsTue 7:00 — 1 commitsTue 8:00 — 0 commitsTue 9:00 — 0 commitsTue 10:00 — 0 commitsTue 11:00 — 0 commitsTue 12:00 — 0 commitsTue 13:00 — 0 commitsTue 14:00 — 0 commitsTue 15:00 — 0 commitsTue 16:00 — 0 commitsTue 17:00 — 0 commitsTue 18:00 — 0 commitsTue 19:00 — 0 commitsTue 20:00 — 0 commitsTue 21:00 — 0 commitsTue 22:00 — 0 commitsTue 23:00 — 0 commitsWed 0:00 — 0 commitsWed 1:00 — 0 commitsWed 2:00 — 0 commitsWed 3:00 — 0 commitsWed 4:00 — 0 commitsWed 5:00 — 0 commitsWed 6:00 — 1 commitsWed 7:00 — 0 commitsWed 8:00 — 0 commitsWed 9:00 — 0 commitsWed 10:00 — 0 commitsWed 11:00 — 0 commitsWed 12:00 — 0 commitsWed 13:00 — 0 commitsWed 14:00 — 0 commitsWed 15:00 — 1 commitsWed 16:00 — 0 commitsWed 17:00 — 0 commitsWed 18:00 — 0 commitsWed 19:00 — 0 commitsWed 20:00 — 0 commitsWed 21:00 — 0 commitsWed 22:00 — 0 commitsWed 23:00 — 0 commitsThu 0:00 — 0 commitsThu 1:00 — 0 commitsThu 2:00 — 0 commitsThu 3:00 — 0 commitsThu 4:00 — 0 commitsThu 5:00 — 0 commitsThu 6:00 — 0 commitsThu 7:00 — 0 commitsThu 8:00 — 0 commitsThu 9:00 — 0 commitsThu 10:00 — 0 commitsThu 11:00 — 0 commitsThu 12:00 — 1 commitsThu 13:00 — 1 commitsThu 14:00 — 0 commitsThu 15:00 — 0 commitsThu 16:00 — 0 commitsThu 17:00 — 0 commitsThu 18:00 — 0 commitsThu 19:00 — 0 commitsThu 20:00 — 0 commitsThu 21:00 — 0 commitsThu 22:00 — 0 commitsThu 23:00 — 0 commitsFri 0:00 — 0 commitsFri 1:00 — 0 commitsFri 2:00 — 0 commitsFri 3:00 — 0 commitsFri 4:00 — 0 commitsFri 5:00 — 0 commitsFri 6:00 — 0 commitsFri 7:00 — 0 commitsFri 8:00 — 0 commitsFri 9:00 — 0 commitsFri 10:00 — 0 commitsFri 11:00 — 0 commitsFri 12:00 — 0 commitsFri 13:00 — 0 commitsFri 14:00 — 0 commitsFri 15:00 — 0 commitsFri 16:00 — 0 commitsFri 17:00 — 0 commitsFri 18:00 — 1 commitsFri 19:00 — 0 commitsFri 20:00 — 0 commitsFri 21:00 — 0 commitsFri 22:00 — 1 commitsFri 23:00 — 0 commitsSat 0:00 — 0 commitsSat 1:00 — 0 commitsSat 2:00 — 0 commitsSat 3:00 — 0 commitsSat 4:00 — 0 commitsSat 5:00 — 0 commitsSat 6:00 — 0 commitsSat 7:00 — 0 commitsSat 8:00 — 0 commitsSat 9:00 — 0 commitsSat 10:00 — 0 commitsSat 11:00 — 0 commitsSat 12:00 — 0 commitsSat 13:00 — 0 commitsSat 14:00 — 1 commitsSat 15:00 — 0 commitsSat 16:00 — 0 commitsSat 17:00 — 0 commitsSat 18:00 — 1 commitsSat 19:00 — 0 commitsSat 20:00 — 0 commitsSat 21:00 — 1 commitsSat 22:00 — 0 commitsSat 23:00 — 0 commits
Commit volume by weekday and hour (UTC). Larger dots mean more commits.
DateListRankStars gained
Sep 6, 2026monthly#12+4,433
Sep 5, 2026monthly#12+4,433
Sep 4, 2026monthly#12+4,425
Aug 16, 2026weekly#3+1,549
Aug 15, 2026weekly#3+1,549
Aug 10, 2026daily#8+432
Aug 9, 2026daily#8+432
Aug 8, 2026daily#9+516
  • ultraworkers/claw-code

    An agent-managed museum exhibit, built in Rust with Gajae-Code / LazyCodex — developed and maintained with no human intervention.

    195.2K stars · Rust

  • farion1231/cc-switch

    A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io

    140K stars · Rust

  • openai/codex

    Lightweight coding agent that runs in your terminal

    127.8K stars · Rust

  • denoland/deno

    A modern runtime for JavaScript and TypeScript.

    108.6K stars · Rust

  • ruvnet/RuView

    π RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — all without a single pixel of video.

    96.4K stars · Rust

  • oven-sh/bun

    Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one

    96.1K stars · Rust