> For AI agents: the complete Sanity documentation index is available at [https://www.sanity.io/docs/llms.txt](https://www.sanity.io/docs/llms.txt).

# Content release document flow

How Content Releases store document versions, and the states a release moves through from creation to publish.

Content Releases let you organize and schedule updates across multiple documents. You can plan, preview, and validate significant changes in advance, then publish them together.

This document explores interacting with Content Releases using Sanity's APIs. For details on using Content Releases in Sanity Studio, or customizing the experience, follow these links:

[Content Releases user guide](https://www.sanity.io/docs/user-guides/content-releases)
Create, schedule, and publish releases from Sanity Studio.

[Content Releases configuration](https://www.sanity.io/docs/studio/content-releases-configuration)
Configure Content Releases in Sanity Studio

**This is a paid feature**
This feature is available on certain Enterprise plans. [Talk to sales](https://www.sanity.io/contact/sales?ref=docs) to learn more.

> [!NOTE]
> Scheduled Drafts is also available
> For teams on Growth or above plans, or that don’t need to schedule groups of documents to go out at once, the [Scheduled Drafts](https://www.sanity.io/docs/studio/scheduled-drafts) feature is available.

APIs that interact with Content Releases require API version `v2025-02-19` or later. A single release can contain a maximum of 1,000 documents, and the combined JSON of all documents in a release cannot exceed 100 MB. Asset files linked from those documents don't count toward the size limit.

## Releases and document versions

Releases are Sanity documents with a type of `system.release`. The top-level `state` property holds the release state, and `metadata` holds the user-supplied fields such as `metadata.title`, `metadata.description`, `metadata.releaseType`, and `metadata.intendedPublishAt`.

> [!TIP]
> Protip
> If you use [content resources and custom roles](https://www.sanity.io/docs/user-guides/roles), you can restrict access for:
> 1. Editing documents *in* releases by using a filter like `_id in path("versions.**")` for any release or `_id in path("versions.rA29bfjqa.**")` for documents in a specific release.
> 2. Performing release actions such as creating, publishing and archiving releases by using a filter like `_id in path("_.releases.**")` for any release or `_id == "_.releases.rA29bfjqa"` for a specific release.

Releases and documents are connected by a document ID system similar to the `drafts.` syntax. For releases, document IDs start with the `versions.` prefix. For example:

- The published version: `movie_70981`
- A release version: `versions.RELEASE_NAME.movie_70981`

Releases have a name, not to be confused with the user-supplied title. This name matches the end of the `_id`. When you create a release through the API, the `releaseId` you supply becomes the name; `client.releases.create()` generates one for you if you omit it. For example, a release name of `rSC2jjcUJ` results in an `_id` of `_.releases.rSC2jjcUJ`.

## Release states

The current status of a release is known as the release `state`. Releases begin in the `active` state. This information is available on the `state` property in documents with a `_type` of `system.release`.

<div style="display:none">Unknown block type "mermaidDiagram", specify a component for it in the `components.types` option</div>A release may have the following states (`state`):

- `active`: The general state of a release that is not within one of the other states. *This is the default state of a new release*.
- `scheduled`: A state resulting from calling the `sanity.action.release.schedule` action on the release or scheduling the release in Studio.
- `published`: A state resulting from either calling the `sanity.action.release.publish` action, publishing the release in Studio, or when a scheduled release is published due to reaching its `publishAt` time.
- `archived`: A state resulting from calling the `sanity.action.release.archive` action or archiving the release in Studio.

There is no `deleted` state. The `sanity.action.release.delete` action, or deleting the release in Studio, removes the release document. You can only delete a release that is `published` or `archived`.

> [!WARNING]
> Gotcha
> When `scheduled`, any version documents that are part of the release are locked. To mutate these documents, either in Studio or programmatically, the release must have a `state` of `active`.

Additional transient states exist to indicate the asynchronous points when releases move between states:

- `scheduling`/`unscheduling`: Intermediate states that exist when moving to or from the `scheduled` state.
- `archiving`/`unarchiving`: Intermediate states that exist when moving to or from the `archived` state.
- `publishing`: Intermediate state that exists before reaching the `published` state. A scheduled release also transitions through `publishing`.

### State transitions

Releases begin in `active`. Every other state is reached through one of these transitions:

- Scheduling or publishing an `active` release moves it to `scheduling`, then `scheduled`.
- Unscheduling a `scheduled` release moves it to `unscheduling`, then back to `active`.
- A `scheduled` release moves to `publishing` when its publish time arrives, then to `published`.
- Archiving an `active` release moves it to `archiving`, then `archived`.
- Unarchiving an `archived` release moves it to `unarchiving`, then back to `active`.
- Deleting a `published` or `archived` release removes the release document.

If publishing or archiving fails, the release returns to `active` and the `error` property holds the reason. Large releases publish, archive, and unarchive in batches, so they can stay in `publishing`, `archiving`, or `unarchiving` across several updates.

A scheduled release stores its publish time in the top-level `publishAt` property. This is distinct from `metadata.intendedPublishAt`, which records the time an editor picked in Studio. Where both are set, `publishAt` takes precedence.

Even releases set for immediate publishing move through the scheduling and scheduled states. They do not stay there; they immediately move on to publishing. Keep this in mind if you listen for state changes on release documents.

## Query releases and versions

Releases are Sanity documents and respect the existing query and mutation APIs. The Content Releases API cheat sheet provides examples of querying and interacting with releases and their documents.

[Content Releases API cheat sheet](https://www.sanity.io/docs/apis-and-sdks/content-releases-cheat-sheet)
Common patterns for querying and interacting with releases and their documents

## Additional resources

[Actions API reference](https://www.sanity.io/docs/http-reference/actions)
Reference documentation for the Actions HTTP endpoint, including the release actions.

[GROQ functions](https://www.sanity.io/docs/specifications/groq-functions)
GROQ queries can use the releases::all(), sanity::partOfRelease(), and sanity::versionOf() functions to retrieve release information.

[@sanity/id-utils](https://github.com/sanity-io/id-utils)
This utility library helps parse and convert between the various ID formats.

