Skip to main content

Multi Environment Publishing Flow With Sanity CMS

Sanity is one of the most flexible and customizable Headless CMS. Working with this Headless CMS and customizing it we can finally get the exact functionality we need and gain a deeper understanding of how it works under the hood.

This article is a compilation of ideas and experiences we gained while working on a large project with an extended publishing flow.

Who is this article for?

This article will be useful for those who have already mastered the basic functionality of Sanity and want to look under the hood of Sanity. In the course of solving the problem, we will go through such points as:

  • Published/Draft document revisions
  • Issuing custom tokens for the front and filtering issuance based on them
  • Replace the Publish button with a set of our custom actions
  • Learn to determine the current user and creator of the document
  • Practice with GROQ queries

Also, this material will be useful to all those who have similar tasks ahead: custom publishing flow, advanced staging, and so on. In addition, even if you have not worked with Sanity before and are considering using this CMS, you can also learn something useful from this article.

Problem statement

Out of the box, Sanity offers two states for a document: draft and published. We want to extend the document life cycle and add intermediate states. These can be additional stages of approval, preview, or staging. Our approach allows you to add any number of them. We also want to preview how a particular stage's content looks on our website or application. In other words, we want to have environments that correspond to the possible states of the documents. We will see the same application in each environment, but only with the corresponding set of documents.

Suppose our publishing flow is quite complex and consists of the following steps:

State levelDocument state nameMeaningAccess Role
0PublishedDocuments in productionChief Publisher
1ApprovedReady to publishChief Publisher
2ReviewSent for approval by the editor-in-chiefChief Editor
3WorkingPreview of the created documentContent Editor
4InitNew draftsContent Editor

For our article, it does not matter why these stages of documents are specifically needed. We only assume two points:

  1. the document will move sequentially from one stage to another
  2. the different document stages can be under the ​​responsibility of different people.

In the Access Role column, we have given the possible roles of employees working with the document at this stage and having the right to transfer the document to the next stage. Again, In other cases, the number of stages may be different.

We also mean that all stages of documents are ranged linearly, and we can say that one or another status is higher or lower than another (see State level value). In our case, the most important status is Published, with a state level of 0. The status with the highest State level is Draft. It is received by newly created documents.


For each possible document state, we want to have a separately deployed version of the application to preview the corresponding documents. Let's say it's a web application, and each environment is deployed to its URL. Let's think about what we want to display in each environment. In production, we will only show Published content. In the preproduction environment, we want to display content with the status Published and Approved.

Why both? There are two nuances here. First, when opening the preproduction environment, the editor-in-chief wants to see the site in the way it will get after the publication of all Approved documents. Second, the content can consist not only of stand-alone documents but also have links to other documents with a higher status. The simplest example is that publications can have links to an author defined by a separate document. And most likely, the author will be contained in a document already in production. Likewise, all other environments will display documents of the same or higher status. Of course, this primarily depends on your content model and your publishing flow, but we will further consider this approach as the most common.

EnvironmentMax State levelPermitted Document Stages

Document editing

Often, the life cycle of a document does not stop after being published to production. You may need to edit a document. The new version of the document will have to go through the same stages again. However, until the edited version is published, we want the old version of the document to remain in production.

This feature is usually provided out of the box by any Headless CMS, and Sanity is no exception. However, Sanity gives us direct access to both versions of the documents and gives us the flexibility to customize our CMS.

[Sanity CMS] itself solves this in the following way. Every document can have two revisions by default: draft and published. The draft version is the one you edit. It has an ID like "" where drafts. is a prefix indicating that this is a draft revision of the document. The published version is created when you click on "Publish" in the Sanity Studio editor. It has the same ID as the draft document but without the prefix. The published version cannot be edited directly so that it can be treated as a kind of locked version of the document. When you need to edit a published document, Sanity Studio automatically creates a new draft revision, which is essentially a clone of the published document, only with “drafts.” in ID. By the way, the editor can determine the presence of a draft revision and opens it for editing even if you send it a link to the published document.

When the editable version of the document is ready, we can publish it. This action performs the following steps. 1.Delete previous revision with Published status (ID xxx-yyy-zzz) 2.Create new revision with Published status by cloning the current version with updated status and removing ID prefix 3.Drop status of the current revision to Draft

Note that Sanity Studio's built-in Publish operation in the third step simply deletes the draft revision of the document. By default, it will only be created again when we start editing the published document. Also, Sanity Studio does not change the values ​​of the document fields when publishing (with the exception of the ID field, where the prefix is ​​removed).

However, in our case, additional steps are required. Now let's pay attention to the third step - we create a draft version of the document in advance and change the necessary field values. This is necessary so that when we start editing this document, the version prepared for this would already open in the editor.

From the Frontend point of view when we receive content, there may be a situation where there are two revisions for one document - with different stages and so having different content. We need a rule to decide which version of the document to show. Obviously, this depends on the app environment. For example, let's consider a document that has already been published, but then was re-edited and its new version is in the process of approval.

Example Document Stages
State namesPublishedReview
State levels02

If we look at table 2, we can see that in the production environment can be shown only published documents. In preproduction, we will show the Published version as well. But on the Approval environment, we can display both documents with the Published status and with the Review status. We will display the version with the Review status, because. this is exactly what the editor will need to see in order to reconcile changes to the document. Similarly, on Integration and Draft, we will display the Review version of the document.

EnvironmentDocument Stage
Production (max: 0)Published (0)
Preproduction (max: 1)Published (0)
Approval (max: 2)Review (2)
Integration (max: 3)Review (2)
Draft (max: 4)Review (2)

Based on the above example, we can derive a general rule.

Rule 2. Revision selection

  • you should display the version with the highest State level allowed in this environment if there is such a version of the document.

Documents Availability

While we're here, let's make another important point for us. For public datasets, only published revisions of documents are available for download. In other words, unauthorized users can only see documents that do not contain drafts. in ID. This approach is quite logical since it protects non-published documents from public review.

Given the above, we get the following:

Revision typeEnvironmentDocument Stages

In other words, only published content can be in the public domain. Documents with all other statuses will be protected, for which reason their IDs will contain the “drafts.” prefix. You can download such documents only if you have an authorization token.

Now we outlined the basic requirements for our publishing flow. In order to implement this scheme in practice, we need to keep in mind two questions:

  • How we will work with documents in Sanity Studio?
  • How will we get the right versions of content on Frontend?

What exact steps and solutions do you need to implement all this in your Sanity CMS? We will consider this in the next article.


Oleg Proskurin

Oleg Proskurin

TechLead at FocusReactive