celld

celld documentation

celld is a self-hosted distributed system that you program like a database. Each Durable Object is its own SQLite database with a single writer, addressed by name and continuously replicated to an S3-compatible bucket you own. A fleet of celld nodes coordinates through that bucket alone — no control plane, no membership service, no consensus — running Cloudflare Workers and Durable Objects on your own machines.

Because state is partitioned into one small database per object from the first line of code, applications shard by construction. The contention, hot spots, and blast-radius failures of a single shared database are designed out rather than managed: a runaway object can only affect its own cell.

Contents

Install

The installer downloads the celld binary. Running a node also needs Litestream on PATH (or LITESTREAM_BIN), and Worker projects deployed with celld deploy need esbuild. Asset-only projects do not:

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

Put ~/.local/bin on PATH if the installer asks you to. Install an exact immutable release by setting CELLD_VERSION to its tag, such as v0.0.1. Rerun the installer with a previous tag to roll back both binaries. Releases are published on GitHub with GitHub Actions build attestations; verify any downloaded asset with gh attestation verify <asset> --repo denoland/celld.

Configure object storage

celld uses the standard AWS credential chain. For Cloudflare R2, create a bucket and an S3 API token with access to that bucket, then set:

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

Treat access to the fleet bucket and its credentials as fleet-administrator access. The bucket contains deployments, SQLite replicas, ownership records, node leases, and the peer-authentication secret.

Deploy an application

Install esbuild on PATH when the project includes Worker code, then run celld deploy from a supported Wrangler project:

git clone https://github.com/denoland/celld
cd celld/examples/counter
celld deploy . \
  --bucket "$CELLD_BUCKET" \
  --endpoint "$S3_ENDPOINT" \
  --region "$AWS_REGION"

celld deploy supports module Workers, Durable Object bindings, and co-deployed or asset-only static assets. The asset subset includes the assets binding, HTML and not-found handling, worker-first routes, _headers, and _redirects. It refuses unknown Wrangler configuration rather than silently dropping it. See the v0.0.1 limitations for the current deployment boundary.

Start a node

For local development, the default listener is enough:

celld \
  --bucket "$CELLD_BUCKET" \
  --endpoint "$S3_ENDPOINT" \
  --region "$AWS_REGION"

For a reachable fleet node, bind the service and advertise the address other nodes and ingress can actually reach:

celld \
  --bucket "$CELLD_BUCKET" \
  --endpoint "$S3_ENDPOINT" \
  --region "$AWS_REGION" \
  --listen 0.0.0.0:8080 \
  --advertise node-a.internal:8080

Add nodes

Start every node with the same bucket settings and a distinct reachable --advertise address. Nodes discover one another through bucket leases; there is no join command and no fixed membership list.

The bucket provides discovery and authority, not network reachability. Peer HTTP is versioned, body-bound, HMAC-authenticated, clock-bounded, and replay-protected, but v0.0.1 does not terminate TLS. Put advertised addresses on a trusted private network or an encrypted overlay such as WireGuard or Tailscale. Do not expose the peer port directly to the public internet.

Diagnose a fleet

celld diagnose reads the bucket's node leases and directly probes every live peer without acquiring a lease or changing ownership:

celld diagnose \
  --bucket "$CELLD_BUCKET" \
  --endpoint "$S3_ENDPOINT" \
  --region "$AWS_REGION"

Use --peer NODE_ID one or more times to restrict the probes. The report distinguishes expired records, unsafe or malformed advertised addresses, unreachable peers, authentication failures, and protocol incompatibility.

Environment variables

celld -h is the authoritative compact list. The main settings are:

variable purpose
CELLD_BUCKET Fleet bucket, equivalent to --bucket
S3_ENDPOINT S3-compatible endpoint, equivalent to --endpoint
AWS_REGION, AWS_DEFAULT_REGION Storage region
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN Explicit AWS credentials; the normal AWS credential chain is also supported
CELLD_ADDR Listener, equivalent to --listen
CELLD_ADVERTISE Peer-reachable address, equivalent to --advertise
CELLD_UNSAFE_PUBLIC_ADVERTISE Permit a literal public peer IP when set to on
CELLD_NODE Explicit node-session ID
CELLD_WATCH Local SQLite/Litestream working directory
LITESTREAM_BIN Litestream executable path
CELLD_ESBUILD esbuild executable path
CELLD_WORKERS Stateless Worker pool size (default: 16)
CELLD_ACTIVATIONS Concurrent cold-cell activation limit (default: the smaller of Worker count and 128)
CELLD_WORKER_LOADER Bind a Worker Loader (Code Mode) at this env name so a Worker can spawn isolates at runtime; off unless set (experimental)
CELLD_MAX_LOADED_WORKERS Cap on concurrent dynamically-loaded workers (default: 256)
CELLD_MAX_RESIDENT_CELLS, CELLD_RESIDENT_LOW_WATER Resident-cell pressure thresholds
CELLD_MAX_RSS_MB, CELLD_MAX_CPU_PERCENT Linux process-pressure thresholds
CELLD_VAR_*, CELLD_VARS_FILE Worker variable overrides
GOMEMLIMIT Litestream Go heap limit (default child: 512MiB)
RUST_LOG Runtime log filter

The help output also names the advanced runtime tuning switches and their defaults.

Edit this page on GitHub