Skip to main content
Document operations provide methods to perform actions on documents through the Studio. All operations check permissions and document state before executing.

OperationsAPI

The operations API is returned by useDocumentOperation() and provides methods for document lifecycle management.
import {useDocumentOperation} from 'sanity'

function MyComponent({documentId, documentType}: Props) {
  const ops = useDocumentOperation(documentId, documentType)
  
  // Check if operation is available
  if (!ops.publish.disabled) {
    ops.publish.execute()
  }
}

Operation Interface

All operations share a common interface:
interface Operation<ExtraArgs extends any[] = [], ErrorStrings extends string = string> {
  disabled: false | ErrorStrings | 'NOT_READY'
  execute(...extra: ExtraArgs): void
}
disabled
false | string
Returns false if the operation can be executed, or a string indicating why it’s disabled:
  • 'NOT_READY' - Document state not yet loaded
  • Operation-specific error strings (see individual operations below)
execute
function
Executes the operation. Some operations accept additional arguments.

publish

Publishes the current draft version of a document.
ops.publish.execute()

Disabled States

  • 'NOT_READY' - Document not loaded
  • 'LIVE_EDIT_ENABLED' - Document type has live edit enabled
  • 'ALREADY_PUBLISHED' - No unpublished changes
  • 'NO_CHANGES' - Draft has no changes to publish

unpublish

Unpublishes a document, keeping only the draft version.
ops.unpublish.execute()

Disabled States

  • 'NOT_READY' - Document not loaded
  • 'LIVE_EDIT_ENABLED' - Document type has live edit enabled
  • 'NOT_PUBLISHED' - Document is not published

delete

Deletes the document (both draft and published versions).
// Delete all versions
ops.delete.execute()

// Delete specific versions
ops.delete.execute(['draft'])
ops.delete.execute(['published'])
ops.delete.execute(['draft', 'published'])
versions
string[]
Array of version identifiers to delete. If not provided, deletes all versions.
  • 'draft' - Delete draft version
  • 'published' - Delete published version

Disabled States

  • 'NOT_READY' - Document not loaded
  • 'NOTHING_TO_DELETE' - No document versions exist

discardChanges

Discards draft changes, reverting to the published version.
ops.discardChanges.execute()

Disabled States

  • 'NOT_READY' - Document not loaded
  • 'NO_CHANGES' - No draft changes to discard
  • 'NOT_PUBLISHED' - Document has no published version to revert to

duplicate

Duplicates the document with a new ID.
// Simple duplication
ops.duplicate.execute('new-document-id')

// With document transformation
ops.duplicate.execute('new-document-id', {
  mapDocument: (doc) => ({
    ...doc,
    title: `${doc.title} (Copy)`,
  })
})
documentId
string
required
The ID for the new duplicated document
options
object
Duplication options
mapDocument
(doc: SanityDocumentLike) => SanityDocumentLike
Function to transform the document before creating the duplicate

Disabled States

  • 'NOT_READY' - Document not loaded
  • 'NOTHING_TO_DUPLICATE' - No document exists to duplicate

patch

Applies patches to a document.
ops.patch.execute([
  {
    set: {
      title: 'New Title'
    }
  }
])

// With initial document for new documents
ops.patch.execute(
  [{set: {title: 'Title'}}],
  {_type: 'article'}
)
patches
Patch[]
required
Array of patch operations to apply
initialDocument
Record<string, any>
Initial document to create if it doesn’t exist

commit

Commits pending mutations.
ops.commit.execute()
This operation batches and executes any pending mutations on the document.

restore

Restores a document to a previous revision.
import {type DocumentRevision} from 'sanity'

function RestoreButton({revision}: {revision: DocumentRevision}) {
  const ops = useDocumentOperation(revision.documentId, revision.documentType)
  
  return (
    <button 
      onClick={() => ops.restore.execute(revision)}
      disabled={!!ops.restore.disabled}
    >
      Restore this version
    </button>
  )
}
revision
DocumentRevision
required
The document revision to restore

Example: Custom Publish Button

import {useDocumentOperation} from 'sanity'
import {Button} from '@sanity/ui'

function CustomPublishButton({id, type}: {id: string, type: string}) {
  const ops = useDocumentOperation(id, type)
  
  const canPublish = !ops.publish.disabled
  const publishLabel = canPublish 
    ? 'Publish'
    : ops.publish.disabled
  
  return (
    <Button
      text={publishLabel}
      tone="positive"
      disabled={!canPublish}
      onClick={() => canPublish && ops.publish.execute()}
    />
  )
}

Example: Bulk Operations

import {useClient, useDocumentOperation} from 'sanity'

function BulkPublisher({documentIds}: {documentIds: string[]}) {
  const client = useClient({apiVersion: '2024-01-01'})
  
  const publishAll = async () => {
    const transaction = client.transaction()
    
    for (const id of documentIds) {
      // Build transaction with multiple publish mutations
      const draftId = `drafts.${id}`
      transaction.createIfNotExists({_id: id, _type: 'article'})
      transaction.patch(id, patch => patch.set({
        // Copy draft content to published
      }))
      transaction.delete(draftId)
    }
    
    await transaction.commit()
  }
  
  return <Button onClick={publishAll}>Publish All</Button>
}

Build docs developers (and LLMs) love