Workers answer requests; Durable Objects own named state

Goal: decide where a piece of state lives on Cloudflare, and address it by name.

A Worker is Cloudflare’s program that answers requests. It runs your code in an isolate, a lightweight sandbox inside the Workers runtime. A Durable Object is a Worker with a globally unique name and its own storage. What are Durable Objects?

Why a Worker must not rely on module state

Module state can outlive a request, and that is the problem. Cloudflare lists three facts. How Workers works

So Cloudflare recommends that you do not use or mutate global state. rat-stack fences that advice with the rat-stack-patterns/no-module-level-mutable-state lint rule:

scripts/oxlint-plugin-patterns.ts · a3f5a148 · no-module-level-mutable-state
      moduleState:
        "Module-level let and var hold state that outlives one request. Every request a Worker isolate or server process handles shares it, so one request's state leaks into the next. Fix: keep the state in a `Ref` inside a Layer, a Durable Object, or the database.",

The fix names three homes for state. This page covers the Durable Object.

What a Durable Object adds

Cloudflare lists these properties. What are Durable Objects?

Worked example: one object per join submission

The join intake keeps each submission’s contact in its own Interest object. The contact lives under one storage key:

apps/site/src/interest/join-contact-cell.ts · a3f5a148 · One key per object
export const JOIN_CONTACT_KEY = "join-contact";
apps/site/src/interest/join-contact-cell.ts · a3f5a148 · The cell reads that key from the storage it is given
export const joinContactCell = (storage: JoinCellStorage) => {
  const current = storage.get(JOIN_CONTACT_KEY).pipe(

The Interest object hands the cell its own storage:

apps/site/src/interest/interest-durable-object.ts · a3f5a148 · The cell is backed by the object's storage
        ...joinContactCell({
          delete: (key) => storage(state.storage.delete(key)),
          get: (key) => storage(state.storage.get(key)),
          put: (key, value) => storage(state.storage.put(key, value)),
        }),

The Worker binds the namespaces once, in its init phase:

apps/site/src/worker.ts · a3f5a148 · Bind the Durable Object namespaces
  const legacyMcp = yield* LegacyMcp;
  const interests = yield* Interest;
  const interestIndex = yield* InterestIndex;

Then it picks an object by name for each request:

apps/site/src/worker.ts · a3f5a148 · One object per submission; one object for the index
          () => interestIndex.getByName("index").applicationIds(),
          (actor) => interests.getByName(intakeInstance(actor))
        ),
        contacts: (submissionId: string) =>
          interests.getByName(`join:${submissionId}`),

The name is the design decision. One name per submission keeps each record apart. One fixed name makes a single place that every request shares.

Choose the home

The lint fix names three homes: a Ref inside a Layer21, a Durable Object, or the database. Pick a Durable Object when several clients must work through one named place. Cloudflare describes that use as coordination. What are Durable Objects?

Work that must finish after the response needs a recovery record too. See Request lifetime is not durability9.

Next

Read Queues, Pipelines, Workflows and K2 do different jobs8 for work that leaves the request. Then read Worker init runs twice8 for a boundary inside the Worker’s own startup.

Interest signup14 describes the whole join flow.

Sources

  1. How Workers works. Cloudflare. One instance may handle many requests, including concurrent ones; isolates can be evicted; requests may reach any instance; do not use or mutate global state. Accessed 2026-11-08.
  2. What are Durable Objects?. Cloudflare. A Worker with a globally unique name and private, strongly consistent storage; single-threaded; in-memory state resets on hibernation; alarms. Accessed 2026-11-08.
  3. rat-stack pattern lint rules. GitHub joelhooks/rat-stack. no-module-level-mutable-state and its fix message. Accessed 2026-11-08.
  4. Interest Durable Object. GitHub joelhooks/rat-stack. Backs the join contact cell with the object's own storage. Accessed 2026-11-08.
  5. Join contact cell. GitHub joelhooks/rat-stack. Stores one sealed contact under the join-contact key. Accessed 2026-11-08.
  6. Mischief Worker composition. GitHub joelhooks/rat-stack. Binds the Interest and InterestIndex namespaces and addresses objects with getByName. Accessed 2026-11-08.

Last changed 2026-11-08 in fa39fa0. Source on GitHub. Change log.

Linked from

  1. add-a-feature-flag. Declare a typed feature flag, its scoped evidence ladder, approval roles, removal date, and durable ledger adapter.

    Each flag and scope routes to its own Durable Object.

  2. Agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.

    Pi Durable and a Cloudflare Container in one Durable Object, compacted together.”

  3. Agent rules for rat-stack (AGENTS.md). What you may change, which commands to run, and which changes need approval.

    85 runs the Worker runtime tests

  4. Alchemy Domain models a business as commands, aggregates, and events. Alchemy Domain is a domain-driven design framework for Effect whose one model runs in memory for tests and on Cloudflare Durable Objects in production.

    On Cloudflare, every aggregate instance, view key, and policy gets its own Durable Object, and the app declares none of them.

  5. Analytics. One event per HTTP request, stored unchanged for queries to select and interpret later.

    withEventCapture wraps the Worker’s fetch handler.¶

  6. Auth. Email and password sign-in through Better Auth, with the signed-in person provided to each RPC call.

    It calls the private LearnFeedbackAuth Worker through a Worker binding.

  7. Bindings. Sam Goodwin describes bindings as the place where runtime permissions and configuration meet infrastructure.

    Goal: connect a Worker to a resource it declares, and see what it gets back.¶

  8. Build and run rat-stack (README.md). What is in the repo, how the example works, and how to run it.

    Role: Private crash-trace archive for the Mischief Worker

  9. Build-time work stays out of requests. Git reads and highlighting produce static assets before the Worker handles requests.

    The Worker reads that output through static assets.¶

  10. CAFE names the Cloudflare, Alchemy, Foldkit and Effect stack. CAFE is a named stack: Cloudflare runs the app, Alchemy declares it, Foldkit draws the UI, and Effect does the typed work.

    The browser and the Worker import the same schemas.

  11. Change log. What changed in the files served here, newest first.

    Workers answer requests; Durable Objects own named state — new page: Initial commit from joelhooks/rat-stack template

  12. Code snippets quote a pinned source. Shipped design brief: pinned Git objects, typed diagnostics, and one build-only snippet model for both views.

    The Worker receives static assets.

  13. Concurrent work needs an owner and a bound. Limit active work, retain result order, and stop child work when its owning lifetime ends.

    Bound worker concurrency and claim every upstream buffer is bounded too.¶

  14. Database. One interface records action runs and their outcomes in either Cloudflare D1 or Postgres through Hyperdrive.

    Auth uses the selected database vendor in the web development backend and the optional private LearnFeedbackAuth Worker.

  15. durability. Keep a rat-stack app standing when a provider, pool, or dependency slows down or a worker dies. Use at any I/O boundary, connection pool, provider call, shared waiter, fan-out, flag, gate, or work that can outlive a request, or when asked "what happens when this is slow", "add a timeout", "make this durable", or "what survives a crash".

    Failure prevented: A healthy restarted worker silently loses accepted work.¶

  16. Durability. Seven durable Effect patterns, each with its seam, its fence, and the incident that taught it.

    The Worker sets it from DROVR_INTAKE_TIMEOUT_SECONDS.

  17. Durability bibliography. Books, checked short quotations, source limits, and Effect mapping provenance.

    Big, Loud Worker-Bees¶

  18. Durability starts with a recovery record. A reading order for storage, replay, worker ownership, overload, and recovery tests.

    Durable work needs storage: A restarted worker cannot recover intent that existed only in memory.¶

  19. Durable work needs storage. A restarted worker cannot recover intent that existed only in memory.

    Choose what must survive termination and how the next worker finds it.¶

  20. Effect + Alchemy peer patterns. Source-grounded patterns from repos on nearby Effect and Alchemy pins.

    These peer patterns guide the web client, Alchemy resources, database, Better Auth, Worker tests, and boundary enforcement.

  21. Effect + Alchemy peers. Public repositories that share rat-stack's prerelease lines.

    Why this tier: Active Oct 27; studied scoped Drizzle, Worker tests, and vendor boundaries.

  22. Effect 4 study: September 2026. Dated Effect 4 source studies from September 2026; current versions live in pins.md.

    For the browser client, Alchemy resources, database, auth, and Worker tests, see Effect + Alchemy peer patterns.

  23. Effect basics. An Effect describes work, expected failures, and required services before a runtime executes it.

    The Worker returns a fetch Effect to its Alchemy Worker adapter:¶

  24. Effect is not BEAM. Fibers share a runtime; scope ownership does not supply isolated heaps or OTP restart strategies.

    Supervision observes worker failure and applies restart policy.

  25. Every task needs an owner. Give child work a lifetime, a failure observer, and a recovery decision.

    Managed worker abstractions make lifecycle policy visible.

  26. Feature flags. Typed feature flags with owners, removal dates, and stable subject rollouts.

    The Worker reads its live value for each captured request.

  27. find-peers. Refresh public peers, exact stack versions, and tiers after stack bumps. On gardener passes, refresh peers checked more than 14 days ago without blocking other work.
    Link context

    Ask DeepWiki (the deepwiki MCP server) one narrow question tied to current work, such as “How does this repo bind a Durable Object to an Alchemy Worker?” Treat the answer as a pointer to files.¶

  28. Flags climb on evidence. A flag ladder connects each rollout step to scoped measurements, approval, and a durable receipt.

    The Durable Object owns the current value and its receipt.

  29. Full agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
  30. Hosted agent interfaces. Discovery documents, HTTP, MCP, A2A, and bounded code mode expose the public reference to agents.

    Older clients initialize sessions backed by a Durable Object, Cloudflare’s feature for persistent state and compute.¶

  31. Interest signup. Agent-only applications start email confirmation through interfaces owned by core and delivery implemented in a separate package.

    The Worker chooses and supplies that implementation when it starts.¶

  32. Learn mode presents concepts at useful depths. An agent presents source-derived concepts during real work and keeps learning events in a private local log.

    On adds Better Auth table migrations and the Worker bindings that use them.¶

  33. Learn the stack | rat-stack. Hands-on guides to Effect actions, XState lifecycles, and the seams between stack pieces.

    durability — Keep a rat-stack app standing when a provider, pool, or dependency slows down or a worker dies.

  34. learn-alchemy. Learn how Alchemy 2 turns an Effect program into a planned Cloudflare deployment.

    One program declares resources, bindings, deployment state, and the Worker that uses them.¶

  35. Lint and type escape ledger (debt.md). A source-linked count of repo-owned lint and type escapes.

    Reason: the object shares its Worker’s environment, which Alchemy types as a dictionary.

  36. model-a-protocol. Check a protocol with a small TLA+ model before you build or change it. Use when steps can interleave or die halfway, such as a crash between two writes, a retry after an unknown outcome, an alarm or sweep that redrives work, or two writers on one record. Also use when asked "can this race?", "what if it dies here?", or "model this", or before a durability design review.

    The Durable Object store writes a record and its sweep index in two calls.

  37. Motion. @rat-stack/motion gives Foldkit apps Penner and CSS easings, tweens, fixed-step springs and interpolation, held in the Model and checked by properties.

    No Worker graph imports the package, so it adds no startup bytes.¶

  38. One program can replace several tool calls. Code mode combines typed content calls inside one bounded execute request.

    ts runs a fresh Dynamic Worker, a Worker loaded to execute sandbox code, with:¶

  39. One prompt serves people and agents. Source-owned agent prompts with typed discovery and copyable browser pages.

    Existing Worker infrastructure serves the assets.

  40. profile-a-worker. Capture a CPU or heap profile of a deployed Cloudflare Worker or Durable Object and read it with pprof. Use when a Worker is slow, burns CPU, nears its memory limit, throws Exceeded Memory, or you need to know which function costs the most in production.

    Cloudflare can sample a deployed Worker or Durable Object while it serves traffic.

  41. query-design. Design or review SQL reads, writes, scans, backfills, and slow database paths. Use before changing a store method or any loop that queries. Covers round-trip arithmetic, batching, keyset paging, index evidence, row budgets, PlanetScale Vitess limits, Hyperdrive connections, statement-count tests, and statement-template fences.

    Create the connection within the Worker request and reuse it for that request’s statements.

  42. Queues, Pipelines, Workflows and K2 do different jobs. Pick a Cloudflare product for work outside a request by the unit you track: a message, a row, a step, or a record in a log.

    A queue holds messages for a consumer Worker.

  43. Rat Stack lore | rat-stack. Short, source-grounded notes on the ideas and decisions behind rat-stack.

    Durability starts with a recovery record — A reading order for storage, replay, worker ownership, overload, and recovery tests.

  44. Rat Stack systems | rat-stack. The systems rat-stack ships, the standard each keeps, and how to check it.

    Turbo remote cache — A separate Worker stores streamed Turbo artifacts in R2, with one credential per team and lifecycle expiry.

  45. rat-stack. An Effect stack so pure (aspirational) Kit Langton will blush.

    Older clients get their own session in a Cloudflare Durable Object, which stores state between requests.

  46. Restart must reconstruct known state. Execution recovery and state recovery need separate contracts.

    Letting a worker fail is useful when recovery returns it to a known state.

  47. Run Effect at the integration boundary. Build the runtime where a calling framework enters, reuse its services, and dispose it when that integration ends.

    The basics page shows CLI, Worker and test execution boundaries.

  48. Schema projections: 2026-09-18 history. Historical Effect rc.115 proposal and implementation receipts from 2026-09-18; use the one-capability-every-surface lore page for the current pattern.

    Runtimes are pluggable: QuickJS, Deno subprocess, Cloudflare dynamic worker, workerd subprocess.

  49. security-audit. Security guidance and vulnerability review for codebases, APIs, services, CLI tools, libraries, and daemons. Use for security questions, focused reviews, vulnerability research, security audits, or pen tests. Run the complete workflow only for explicit codebase audit or pen-test requests, full/comprehensive/end-to-end reviews, or requested report artifacts.

    The Worker adapter is sandbox-worker-loader.ts.

  50. Shared caches hold completed values. Keep pending request I/O out of isolate-scoped caches.

    A Worker isolate can serve several requests.

  51. Source change history (log.md). The generated change log as Markdown.

    Workers answer requests; Durable Objects own named state — new page: Initial commit from joelhooks/rat-stack template

  52. The rat-stack bestiary eats excuses. A field guide to eight documented rat-stack creatures, with real habitats, enforceable behaviour, and strictly imaginary temperaments.

    Worker names, resource IDs, and TypeScript symbols retain their names.

  53. The war stories. Seven public repo incidents: a deploy undoes itself, failure says 200, sessions forget their guests, and the rat tests the demolition instructions.

    ” Alchemy resource IDs, Worker names, and TypeScript symbols keep their names, so Mischief survives the move.¶

  54. There is no ISR on Cloudflare. SvelteKit's Vercel ISR setting does not configure Workers Cache; our local comparison did not prove cache reuse.

    Workers Cache puts a cache in front of a Worker entrypoint.

  55. Trace operations where they mean something. Name useful operations, add safe context, and distinguish creating a span from delivering it to a backend.

    D1 and Durable Object SQL: SQL text; Durable Object SQL also records query bindings¶

  56. Turbo remote cache. A separate Worker stores streamed Turbo artifacts in R2, with one credential per team and lifecycle expiry.

    0 owns a separate Worker, a dedicated R2 bucket, and generated team credentials.

  57. uncomplect. Find responsibilities that a rat-stack design combines, separate them into capabilities, cartridges, machines, features, and clients, and enforce that separation through types and checks. Use when asked to simplify, review, or replace a design, "what would Rich Hickey do", "optimize for deletion", or "define this error out of existence".

    Look for a cache or local copy of server data that decides a mutation independently of the Durable Object or database cartridge.¶

  58. Web. The Foldkit reader renders on the server and prerenders its public pages; the browser hydrates the same view.

    Server rendering means the Worker builds the page HTML for each request.

  59. Worker init runs twice. Alchemy Worker initialization runs in deploy and runtime contexts, so resource declarations need a boundary.

    It runs when Alchemy declares deploy-time resources and when the Worker starts in an isolate, a separate execution environment.

  60. write-a-wiki-page. Write or revise public wiki pages with short prose, cited claims, meaningful visuals, and pinned code snippets.

    Keep it out of new Worker route handlers.¶

Unlinked mentions (32)