---
title: Data retention
description: Control how long a run's data is kept after it finishes.
type: reference
summary: Control how long a run's data is kept after the run ends.
prerequisites:
  - /docs/foundations/workflows-and-steps
related:
  - /docs/observability
  - /docs/api-reference/workflow-api/start
---

# Data retention



A finished run leaves data behind: the inputs and outputs of the workflow and
each of its steps, the payloads on its event log, and anything written to its
streams. How long that data is kept is decided by the World you are running
on, not by the SDK.

`experimental_retention` on [`start()`](/docs/api-reference/workflow-api/start)
lets a run ask for a specific retention period, rather than the World's default.

## Deleting a run's data as soon as it ends

{/* @skip-typecheck: abbreviated usage; processDocumentWorkflow is the reader's own workflow */}

```typescript lineNumbers
const run = await start(processDocumentWorkflow, [documentId], {
  experimental_retention: 0, // [!code highlight]
})
```

`0` asks the World to delete the run's **user data** the moment the run
completes or fails, rather than keeping it for the World's default window.

Two values are accepted today:

| Value       | Meaning                                                       |
| ----------- | ------------------------------------------------------------- |
| `0`         | Delete user data as soon as the run reaches a terminal state. |
| `'default'` | Use the World's default. Identical to omitting the option.    |

<Callout type="warn">
  The option is prefixed `experimental_` because both its name and the set of
  values it accepts are expected to change.
</Callout>

## What is deleted, and what is not

**Deleted:** the run's input, output and error; every step's input, output and
error; the payloads on the event log; and stream contents.

**Kept:** the run, step and event records themselves — their ids, timestamps,
status, step names, and any [attributes](/docs/observability/attributes) you
set. They are kept for the World's default period so the run stays visible in
the CLI and web UI. A purged run is still listed and still traceable; its
payloads simply read back as expired.

Inspecting a purged run shows it as expired rather than failing. The Workflow
CLI renders the run's own input, output and error as `<data expired>`:

```bash
workflow inspect runs wrun_...
```

Step, hook and event payloads read back empty. On the Vercel World they also
render as `<data expired>`; on Worlds that clear the stored value outright
they simply show as empty. Either way the data is gone — the difference is
only in how the absence is labelled.

<Callout type="warn">
  **You cannot read the return value of a run started with
  `experimental_retention: 0`.** The deletion races your own read of the
  result and generally wins, so `await run.returnValue` throws
  [`RunExpiredError`](/docs/errors/run-expired) instead of resolving.

  This is a known limitation. If you need the result, send it somewhere you
  control, e.g. a step that writes it to your own store, rather than reading
  it back off the run.
</Callout>

`RunExpiredError` is not specific to `experimental_retention: 0`. Any run read
after its retention window has passed throws it, and the error carries
`runId`, `runStatus` and `expiredAt` when the World still has them — so a
caller can tell a successful run whose result is gone from a failed one whose
error is gone. If the run's metadata is gone too, the World reports the run as
missing and you get `WorkflowRunNotFoundError` instead.

## Retention is implemented by the World

The SDK records your preference; it does not enforce it. `start()` writes the
value onto the run as the reserved `$retention` attribute, and the World
decides what to do when the run ends. Attributes are a spec version 4 feature,
so `experimental_retention: 0` throws against an older World rather than being
recorded and ignored. A World that does implement spec version 4 but not
retention **keeps the data**. If you need certainty that a specific World
deletes your data, confirm it against that World's own documentation rather
than the presence of this option.


---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)