CellB

KV

env.<BINDING> of a kv_namespaces entry: get, put, delete and the rest of Workers KV. CellB runs celld’s own KV code (services/kv.js, vendored unchanged), so values, limits and error messages are celld’s, and a namespace’s data moves between celld and CellB with its cell.

{
  "name": "kv",
  "main": "index.js",
  "compatibility_date": "2026-01-01",
  "kv_namespaces": [
    {
      "binding": "VALUES",
      "id": "example-values"
    }
  ]
}
export default {
  async fetch(request, env) {
    const key = new URL(request.url).pathname.slice(1);
    if (!key) return new Response("Use /KEY.", { status: 400 });

    if (request.method === "PUT") {
      await env.VALUES.put(key, request.body);
      return new Response(null, { status: 204 });
    }

    if (request.method === "DELETE") {
      await env.VALUES.delete(key);
      return new Response(null, { status: 204 });
    }

    const value = await env.VALUES.get(key);
    return value === null
      ? new Response("Not found.", { status: 404 })
      : new Response(value);
  },
};

This is celld’s kv example (conformance/celld-examples/kv), copied unchanged and run by the conformance suite on Node and in Chromium.

A namespace is a cell

A namespace lives in a cell __KvNamespace:<id>. Its key does not depend on the script, so every project in a fleet that names the same namespace id reads the same data, as on celld. Values above 1 MiB are kept outside the cell, in a FilesApi (celld: the fleet bucket), through celld’s own prepare / put / get / sweep protocol. The limits are celld’s (celld_logic::kv’s constants).

How it is checked

celld’s kv example and CellB’s kv-values and kv-details projects, on Node and in Chromium; e2e/p11f-celld-one-bucket.test.ts moves a namespace’s data celld → CellB → celld through one bucket.

What breaks

Errors carry celld’s messages: KV_ERROR: ….