> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runtype.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runtype.com/_mcp/server.

# Flow versioning and publishing

Use flow versioning to keep an immutable record of a flow at a point in time, to roll back to an earlier definition, and to run one of those snapshots on demand.

## How versioning works

When you edit a flow, you work on an unnumbered **Draft**. Its persistence state is **Saved** or **Unsaved changes**. Click **Save** to record changed configuration.

The first dashboard save creates saved version `v1`. Each changed save creates the next saved version. An unchanged save reuses its snapshot ID.

Publishing activates a saved snapshot. Publishing saved `v4` makes `v4` live without creating `v5`. Further saves leave that publication active.

Products, surfaces, schedules, and unpinned API calls use the published configuration. Flows without a publication use their saved definition for compatibility.

## Version types

Saved versions have visible numbers such as `v1` and `v2`. Test and virtual captures keep their IDs and raw API numbers without advancing saved numbering.

Each version has a type. The following table lists the types and where each one comes from:

| Type        | Created when                                               | Badge in **Version History**         |
| ----------- | ---------------------------------------------------------- | ------------------------------------ |
| `draft`     | You save a configuration.                                  | **saved**                            |
| `published` | You publish a configuration, or a code upsert records it.  | **live** or **previously published** |
| `test`      | You test unsaved changes.                                  | Excluded from default history        |
| `virtual`   | A dispatch captures configuration without a `versionType`. | Excluded from default history        |

Snapshot configuration is immutable. Only one version is live, but former publications retain their publication state. Legacy saved numbers retain gaps and existing identifiers.

Optional text labels annotate versions without replacing their numbers. Legacy entries whose publication history was erased appear as **saved**, without a never-published claim.

To record a labeled snapshot when you run a saved flow, pass these options to `dispatch`. When the request names the flow by ID without steps, the snapshot records the saved definition. When the request includes steps, the snapshot records those steps instead.

```json
{
  "options": {
    "createVersion": true,
    "versionType": "draft",
    "versionLabel": "before-prompt-change",
    "versionNotes": "Snapshot before the summary prompt rewrite."
  }
}
```

## Test before you save and publish

Test in the editor before publishing. A saved draft test pins its snapshot ID. Unsaved tests capture their exact configuration without creating ordinary history entries.

Use the following checks:

1. Run the flow with representative inputs.
2. If the flow has conditional branches, test each branch.
3. Verify that the outputs are correct.
4. Test error cases.
5. Review the execution results.

## Publish a flow

To publish a flow, follow these steps:

1. Make your changes in the editor.
2. Complete the checks in [Test before you save and publish](#test-before-you-save-and-publish).
3. Click **Save options**, the arrow beside the save button, and then click **Publish**.
4. Review the confirmation's saved version and the live version that it replaces.
5. Confirm publication.

Unsaved publication first saves one snapshot, then activates that exact ID. If publication fails, the previous live version stays active and the saved configuration remains recoverable.

The editor shows **Draft · Saved** after saving and **Live · vN** for the active publication. Use **Versions** to recover saved changes after a publication failure.

Publishing requires the `FLOWS:WRITE` permission. An API key without it gets a `403` response. For more information, see [Permissions](/developer-guides/getting-started/authentication#permissions).

## View version history

To view version history, follow these steps:

1. Open the flow.
2. Click **Save options**.
3. Click **Versions**.

The **Version History** sheet lists saved numbers, publication state, author, creation time, and change notes or a step summary.

## Load or publish a previous version

To load an earlier version into the editor, follow these steps:

1. In the flow editor, click **Save options**, and then click **Versions**.
2. Find the version that you want to load.
3. Click **Load**. The editor replaces its current flow name, description, and steps with the selected version.
4. Review and test the loaded version.

Loading changes the working draft without changing live traffic. To publish the existing version ID, use its **Publish** action in **Version History**.

Click **Publish** beside a version and confirm the selected number and the live version being replaced. This activates the existing ID and applies its configuration.

Loading a version, or publishing a version from **Version History**, discards unsaved editor changes. Save your changes first if you need them.

On Enterprise plans, the [audit trail](/user-guide/logs/audit-trail) shows who published each version and when. Each publish records a `flow.published` entry with the published configuration and a `flow.active_version_changed` entry with the previous and new version IDs.

## What each entry point runs

What runs depends on where you start the run:

* **The editor's test run** executes the current editor state. When you have unsaved
  changes, it sends those steps with the run, so the run reflects your edits and also
  records a `test` version snapshot of what ran. When the editor has no unsaved changes,
  it pins the saved draft's snapshot ID. Test results identify the saved version or captured draft used.
* **The `run_flow` MCP tool, and a `dispatch` call that names a flow by ID without steps
  or a version pin**, run the published snapshot, or the saved definition when no publication exists. `run_flow` does not accept a version pin.
* **A `dispatch` call with `options.flowVersionId`** executes that version's stored
  snapshot, so later edits to the saved definition do not affect it. The version ID is
  also recorded alongside the run's persisted step results.

A pinned run never falls back to the saved definition. If the version ID does not exist,
the call returns `404`. If the dispatch can't run the pinned snapshot's steps, the call
returns `422` rather than running a different definition. For the step configurations
that a dispatch can't run, see [Flow validation warnings](/user-guide/flows/flow-validation-warnings).

## Versions created from code

When an SDK upsert changes a flow, Runtype records and publishes the submitted configuration in the same transaction. Its notes summarize the change.

Legacy snapshots created before this saved-version model retain their IDs and content. Unpinned runs use the current saved definition until you explicitly publish a version. This preserves existing execution behavior for dashboard, SDK, and ensure publications. Explicit version selections still run the selected snapshot.

After an upsert creates or changes a flow, the flow counts as managed in code and shows the **Managed in code** badge. Publishing a stored version over it needs confirmation, as described in [Publish a stored version](#publish-a-stored-version).

To roll back an upsert, publish an earlier saved version with explicit overwrite confirmation. To disable snapshots, set `upsertOptions.createVersionOnChange` to `false`.

A changed upsert with snapshots disabled clears version pointers and runs its unversioned saved definition. Existing snapshots and run references remain available.

For flows that you deploy with `ensure`, see [Manage flows as code](/user-guide/flows/manage-flows-as-code).

## Publish from the API, SDK, CLI, or MCP

You can publish the current draft or a specific stored version outside the dashboard.

### Find a version ID

To find a version ID, list the flow's versions:

* REST: `GET /v1/flow-versions/FLOW_ID`. Add `?type=published`, `draft`, `test`, or `virtual` to filter by type.
* TypeScript SDK: `client.flowVersions.list('FLOW_ID')`
* CLI: `runtype flow-versions list FLOW_ID`
* MCP: `list_flow_versions`

Default lists contain saved versions. Use `?type=test` or `?type=virtual` to discover captures explicitly.

The response includes `draftVersionId` and `publishedVersionId`. Each entry includes its ID, raw `versionNumber`, nullable `savedVersionNumber`, type, publication timestamp, author ID, and summary.

Use `savedVersionNumber` for visible numbering. Preserve raw `versionNumber` for existing integrations and use snapshot IDs for exact selection.

To get one version, use `GET /v1/flow-versions/FLOW_ID/VERSION_ID`, `client.flowVersions.get`, `runtype flow-versions get`, or the `get_flow_version` MCP tool. To get the published version, use `GET /v1/flow-versions/FLOW_ID/published`, `client.flowVersions.getPublished`, `runtype flow-versions published`, or the `get_published_flow_version` MCP tool.

### Publish the current draft

To publish the flow's saved draft, call `POST /v1/flows/FLOW_ID/publish`:

```typescript
import { RuntypeClient } from '@runtypelabs/sdk'

const client = new RuntypeClient({ apiKey: process.env.RUNTYPE_API_KEY })
const { publishedVersionId } = await client.flows.publish('FLOW_ID')
```

This saves changed configuration if necessary, then activates that saved snapshot. Unchanged configuration reuses its existing ID.

### Publish a stored version

To publish a specific version, call `POST /v1/flow-versions/FLOW_ID/publish` with the version ID in the body:

```json
{ "versionId": "VERSION_ID" }
```

The following samples publish a stored version from the SDK and the CLI:

```typescript
const result = await client.flowVersions.publish('FLOW_ID', 'VERSION_ID')
console.log(result.applied, result.warnings, result.lastModifiedSource)
```

```bash
runtype flow-versions publish FLOW_ID --version VERSION_ID
```

Replace the following placeholders:

* `FLOW_ID`: the ID of the flow.
* `VERSION_ID`: the ID of the version, from **Version History** or [Find a version ID](#find-a-version-id).

Publishing a stored version from any of these clients has the same effect as clicking **Publish** in **Version History**. Runtype validates the version, writes its name, description, and steps to the saved flow, and marks it as published. Products, schedules, `run_flow`, and unpinned dispatches run that version immediately. Runtype also regenerates the parameter schemas of Product capabilities that use the flow. The response's `applied`, `warnings`, and `lastModifiedSource` fields report what changed.

The call returns the following errors:

| Status | Cause                                                                                                                                    |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | The version fails flow validation, or the version belongs to a different flow.                                                           |
| `403`  | The API key doesn't have the `FLOWS:WRITE` permission, or you don't have access to the flow.                                             |
| `404`  | The flow or the version doesn't exist.                                                                                                   |
| `409`  | The flow's last change came from code, such as an SDK `ensure` or upsert, or Terraform. The body has `code: "managed_by_code_conflict"`. |

A flow whose last change came from code shows a **Managed in code** badge in the editor. The dashboard asks you to confirm before it publishes a version over it. To overwrite a code-managed flow from another client after you confirm the change, pass the overwrite option for your client:

* REST and TypeScript SDK: `onConflict: "overwrite"`, for example `client.flowVersions.publish('FLOW_ID', 'VERSION_ID', { onConflict: 'overwrite' })`
* CLI: `runtype flow-versions publish FLOW_ID --version VERSION_ID --overwrite-managed`
* MCP: `publish_flow_version` with `on_conflict: "overwrite"`
* [Code Mode](/developer-guides/integrations/runtype-mcp-server#chain-platform-tools-from-code-mode): `{ onConflict: "overwrite" }`

## Best practices

Use these practices to manage flow changes:

* Save small, incremental changes. Each save records a draft snapshot that you can load or publish later from **Version History**.
* Test the saved configuration before publishing it to production traffic.
* Review execution logs after you publish.
* To go back to an earlier definition, click **Publish** beside that version in **Version History**, or load it into the editor and save it.

## Next steps

Continue with these guides:

* [Creating and editing flows](/user-guide/flows/creating-and-editing-flows): create and test flows
* [Debugging flows](/user-guide/flows/debugging-flows): investigate execution issues
* [Manage flows as code](/user-guide/flows/manage-flows-as-code): keep flow definitions in your repository
* [Audit trail](/user-guide/logs/audit-trail): see who published each version
* [Execute a flow or agent](/api-reference/runtype-api/dispatch/execute-a-flow-or-agent): the `dispatch` reference, including `options.flowVersionId`