# Durability starts with a recovery record

> For agents: start with the [agent guide](https://ratstack.sh/llms.txt). Every page is Markdown by default; add `Accept: text/html` for HTML.

Free workshop: [Build Agent Loops That Never Stop Shipping](/tokenmaxx#interested).

**Effect is not BEAM.** Fibers do not provide private process heaps or OTP restart strategies. A durable operation needs storage and a recovery owner.

Use [the durability skill](/skills/durability) to review a design. [The durability system page](/systems/durability) shows the patterns rat-stack ships. These pages separate the book principles from our Effect 4.0.0 mappings.

The template pins Effect 4.0.0. Each named API and each absence claim was checked against that release. Check your own Effect [pin](/skills/gardener) before you apply a mapping.

## Reading order

- [Effect is not BEAM](/lore/effect-is-not-beam): Fibers share a runtime; [scope](/lore/scopes-own-resources) ownership does not supply isolated heaps or OTP restart strategies.
- [Durable work needs storage](/lore/durable-work-needs-storage): A restarted worker cannot recover intent that existed only in memory.
- [Every task needs an owner](/lore/every-task-needs-an-owner): Give child work a lifetime, a failure observer, and a recovery decision.
- [Supervision chooses what restarts](/lore/supervision-is-a-recovery-policy): Restart policy follows dependency shape and bounds repeated recovery.
- [Restart must reconstruct known state](/lore/restart-from-known-state): Execution recovery and state recovery need separate contracts.
- [Retry needs idempotent effects](/lore/retry-needs-idempotency): Repeating an operation must preserve its intended observable result.
- [Checkpoints follow the promised commit](/lore/checkpoints-follow-commits): Persist state and progress together when one store can transact both.
- [Replay needs stable inputs](/lore/replay-needs-stable-inputs): Historical processing must not silently depend on today’s clock or external decisions.
- [Old events must still decode](/lore/old-events-must-still-decode): Retained data needs compatibility rules before recovery depends on it.
- [Dead letters need a return path](/lore/dead-letters-need-a-return-path): Exhausted work needs durable evidence, an owner, and deliberate redrive.
- [Timeouts bound waiting](/lore/timeouts-bound-waiting): A local timeout stops waiting; it does not prove the remote action never happened.
- [Retry load needs a budget](/lore/retry-load-needs-a-budget): One retry owner must control attempts, delay, and aggregate load.
- [Circuit breakers have state](/lore/circuit-breakers-have-state): A breaker stops doomed calls and controls probes before restoring traffic.
- [Bulkheads isolate scarce capacity](/lore/bulkheads-isolate-capacity): Reserve independent capacity for workloads that must not starve each other.
- [Backpressure reaches the producer](/lore/backpressure-reaches-the-producer): Bounded consumption helps only when upstream respects waiting or refusal.
- [Admission control protects recovery](/lore/admission-controls-new-work): Refuse or defer work that cannot be served usefully under current load.
- [Steady state recycles resources](/lore/steady-state-recycles-resources): Every accumulation needs a deliberate recycling policy.
- [Queries need result bounds](/lore/queries-need-result-bounds): Limit result cardinality before the driver materializes an oversized response.
- [Failures keep their meaning](/lore/failures-keep-their-meaning): Expected refusals, infrastructure faults, and defects need different policies.
- [Cleanup can be an idempotent postcondition](/lore/cleanup-can-be-an-idempotent-postcondition): Already-absent state can be success when absence is the operation’s intended result.
- [Pure cores reduce timeline coupling](/lore/pure-cores-reduce-timelines): Move deterministic rules out of time-dependent actions and shared mutable state.
- [Recovery needs model tests](/lore/recovery-needs-model-tests): Test sequences of failures and recoveries against explicit invariants.
- [Golden signals expose overload](/lore/golden-signals-expose-overload): Measure latency, traffic, errors, and saturation, including failed work.
- [Shared schemas need a transition period](/lore/schema-changes-need-a-transition): Keep old and new representations usable while consumers migrate.
- [Durable timers need recovery](/lore/durable-timers-need-recovery): Persist scheduled intent when losing a worker must not lose its deadlines.
- [Request lifetime is not durability](/lore/request-lifetime-is-not-durability): Worker waitUntil has a shared post-response allowance; required work needs a durable marker and redrive.

## Existing rat-stack paths

- [Scopes release resources when work ends](/lore/scopes-own-resources).
- [Concurrent work needs an owner](/lore/concurrent-work-needs-an-owner).
- [Lifecycles are machines](/lore/lifecycles-are-machines).
- [The error model](/lore/error-model).
- [Schemas define the boundary](/lore/schemas-define-the-boundary).
- [Accumulate independent errors](/lore/accumulate-independent-errors).
- [Cache completed values](/lore/cache-completed-values).
- [Layers make dependencies explicit](/lore/layers-make-dependencies-explicit).
- [Property-based testing](/lore/property-based-testing).
- [Uncomplect](/skills/uncomplect).
- [Add a lifecycle machine](/skills/add-a-lifecycle-machine).
- [Investigate a failure](/skills/investigate-a-failure).

## Sources

Read [the durability bibliography](/lore/durability-bibliography) for books, sections, and checked short quotations. API names describe the Effect 4.0.0 source.

## Sources

1. [Gray II, James Edward; Tate, Bruce A. Designing Elixir Systems with OTP. Pragmatic Bookshelf, 2019.](https://pragprog.com/titles/jgotp/designing-elixir-systems-with-otp/)
   Pragmatic Bookshelf. Build a Functional Core; Isolate Process Machinery in a Boundary; Customize Your Lifecycle; Big, Loud Worker-Bees; Add Persistence as a Boundary Service; Test the Boundary. Accessed 2026-10-23.

2. [Nygard, Michael T. Release It!: Design and Deploy Production-Ready Software. Pragmatic Bookshelf, 2007.](https://archive.org/details/releaseitdesignd0000nyga)
   Pragmatic Bookshelf. §4.4 Unbounded Result Sets; Chapter 5 Stability Patterns: §5.1 Timeouts, §5.2 Circuit Breaker, §5.3 Bulkheads, §5.4 Steady State, §5.5 Fail Fast, §5.6 Handshaking, §5.7 Test Harness, §5.8 Decoupling Middleware. Accessed 2026-10-23.

3. [Effect contributors. Effect 4.0.0. workflow/WorkflowEngine.ts](https://github.com/Effect-TS/effect/blob/67ba4e46a11ccda0b6761578bfd22c04ae00167d/packages/effect/src/workflow/WorkflowEngine.ts)
   Effect-TS. Pinned source for our Effect mapping, not a claim from the book. Accessed 2026-10-23.

## Lore on this page

- [Dead letters need a return path](/lore/dead-letters-need-a-return-path)
- [Timeouts bound waiting](/lore/timeouts-bound-waiting)
- [Queries need result bounds](/lore/queries-need-result-bounds)
- [Request lifetime is not durability](/lore/request-lifetime-is-not-durability)

## Linked from

- Admission control protects recovery → Refuse or defer work that cannot be served usefully under current load. → [Read page](https://ratstack.sh/lore/admission-controls-new-work)

- Agent guide → An Effect stack so pure (aspirational) Kit Langton will blush. → [Read page](https://ratstack.sh/llms.txt)

- Backpressure reaches the producer → Bounded consumption helps only when upstream respects waiting or refusal. → [Read page](https://ratstack.sh/lore/backpressure-reaches-the-producer)

- Bulkheads isolate scarce capacity → Reserve independent capacity for workloads that must not starve each other. → [Read page](https://ratstack.sh/lore/bulkheads-isolate-capacity)

- Change log → What changed in the files served here, newest first. → [Read page](https://ratstack.sh/log)

- Checkpoints follow the promised commit → Persist state and progress together when one store can transact both. → [Read page](https://ratstack.sh/lore/checkpoints-follow-commits)

- Circuit breakers have state → A breaker stops doomed calls and controls probes before restoring traffic. → [Read page](https://ratstack.sh/lore/circuit-breakers-have-state)

- Cleanup can be an idempotent postcondition → Already-absent state can be success when absence is the operation’s intended result. → [Read page](https://ratstack.sh/lore/cleanup-can-be-an-idempotent-postcondition)

- Concurrent work needs an owner and a bound → Limit active work, retain result order, and stop child work when its owning lifetime ends. → [Read page](https://ratstack.sh/lore/concurrent-work-needs-an-owner)

- Dead letters need a return path → Exhausted work needs durable evidence, an owner, and deliberate redrive. → [Read page](https://ratstack.sh/lore/dead-letters-need-a-return-path)

- 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". → [Read page](https://ratstack.sh/skills/durability)

- Durability bibliography → Books, checked short quotations, source limits, and Effect mapping provenance. → [Read page](https://ratstack.sh/lore/durability-bibliography)

- Durable timers need recovery → Persist scheduled intent when losing a worker must not lose its deadlines. → [Read page](https://ratstack.sh/lore/durable-timers-need-recovery)

- Durable work needs storage → A restarted worker cannot recover intent that existed only in memory. → [Read page](https://ratstack.sh/lore/durable-work-needs-storage)

- Effect is not BEAM → Fibers share a runtime; scope ownership does not supply isolated heaps or OTP restart strategies. → [Read page](https://ratstack.sh/lore/effect-is-not-beam)

- Every task needs an owner → Give child work a lifetime, a failure observer, and a recovery decision. → [Read page](https://ratstack.sh/lore/every-task-needs-an-owner)

- Failures keep their meaning → Expected refusals, infrastructure faults, and defects need different policies. → [Read page](https://ratstack.sh/lore/failures-keep-their-meaning)

- Full agent guide → An Effect stack so pure (aspirational) Kit Langton will blush. → [Read page](https://ratstack.sh/llms-full.txt)

- Golden signals expose overload → Measure latency, traffic, errors, and saturation, including failed work. → [Read page](https://ratstack.sh/lore/golden-signals-expose-overload)

- Old events must still decode → Retained data needs compatibility rules before recovery depends on it. → [Read page](https://ratstack.sh/lore/old-events-must-still-decode)

- Pure cores reduce timeline coupling → Move deterministic rules out of time-dependent actions and shared mutable state. → [Read page](https://ratstack.sh/lore/pure-cores-reduce-timelines)

- Queries need result bounds → Limit result cardinality before the driver materializes an oversized response. → [Read page](https://ratstack.sh/lore/queries-need-result-bounds)

- Rat Stack lore | rat-stack → Short, source-grounded notes on the ideas and decisions behind rat-stack. → [Read page](https://ratstack.sh/lore)

- Recovery needs model tests → Test sequences of failures and recoveries against explicit invariants. → [Read page](https://ratstack.sh/lore/recovery-needs-model-tests)

- Replay needs stable inputs → Historical processing must not silently depend on today’s clock or external decisions. → [Read page](https://ratstack.sh/lore/replay-needs-stable-inputs)

- Request lifetime is not durability → Worker waitUntil has a shared post-response allowance; required work needs a durable marker and redrive. → [Read page](https://ratstack.sh/lore/request-lifetime-is-not-durability)

- Restart must reconstruct known state → Execution recovery and state recovery need separate contracts. → [Read page](https://ratstack.sh/lore/restart-from-known-state)

- Retry load needs a budget → One retry owner must control attempts, delay, and aggregate load. → [Read page](https://ratstack.sh/lore/retry-load-needs-a-budget)

- Retry needs idempotent effects → Repeating an operation must preserve its intended observable result. → [Read page](https://ratstack.sh/lore/retry-needs-idempotency)

- Shared schemas need a transition period → Keep old and new representations usable while consumers migrate. → [Read page](https://ratstack.sh/lore/schema-changes-need-a-transition)

- Source change history (log.md) → The generated change log as Markdown. → [Read page](https://ratstack.sh/log.md)

- Steady state recycles resources → Every accumulation needs a deliberate recycling policy. → [Read page](https://ratstack.sh/lore/steady-state-recycles-resources)

- Supervision chooses what restarts → Restart policy follows dependency shape and bounds repeated recovery. → [Read page](https://ratstack.sh/lore/supervision-is-a-recovery-policy)

- Timeouts bound waiting → A local timeout stops waiting; it does not prove the remote action never happened. → [Read page](https://ratstack.sh/lore/timeouts-bound-waiting)
