Creating draft edits programmatically with the Sanity client for JavaScript

5 replies
Last updated: Aug 3, 2022
Hi All!
Is there a way to create a draft edit programatically with the sanity client for javascript. Create or replace works in creating a draft update but this then triggers the create event for a webhook.

I want to use patch to trigger the edit event for my webhook but I don't seem to be able to make patch create a draft update.
AI Update

You're running into the fundamental difference between how patch and create operations work. Here's what's happening and the correct approach:

The Core Issue

The patch operation in Sanity only works on existing documents - it cannot create new documents. When you want to create a draft programmatically, you need to create a new document with the drafts. prefix in the _id. Since this is a creation operation (not modifying an existing document), you must use a create-type mutation like createOrReplace.

From the Mutation API documentation, the available create operations are:

  • create - Creates a new document, fails if _id already exists
  • createIfNotExists - Creates only if the _id doesn't exist
  • createOrReplace - Creates or replaces a document with that _id

The Solution

Use createOrReplace with the draft _id:

client.createOrReplace({
  _id: `drafts.${documentId}`,
  _type: 'yourDocumentType',
  // ... your document fields
})

Why this triggers a "create" webhook event: In Sanity's architecture, a draft is a separate document from its published counterpart - it just has drafts. prepended to the _id. When you use createOrReplace with drafts.post-123, you're creating (or replacing) that specific draft document, which the webhook system correctly identifies as a create event for that document ID.

Better Alternative: Sanity Functions

Since you're using webhooks to react to content changes, I'd strongly recommend switching to Sanity Functions instead. Functions are the modern, recommended approach for automation and event handling in Sanity, with several advantages:

  • Native integration - Direct access to document events without external hosting
  • Better event filtering - Distinguish between draft and published changes more easily
  • No infrastructure - Serverless compute runs on Sanity's infrastructure
  • Automatic scaling - Handles traffic spikes automatically
  • More precise control - Configure triggers for specific document events (publish, create, update, delete)

Functions can handle the same use cases as webhooks but with tighter integration and less complexity around event types.

Workaround for Webhooks

If you need to stick with webhooks, you can distinguish between "true creates" and "draft updates" by:

  1. Checking for the published version - When your webhook receives a create event for a draft ID, query whether the published version exists:

    const publishedExists = await client.fetch(
      `defined(*[_id == $publishedId][0])`,
      { publishedId: documentId.replace('drafts.', '') }
    )
    // If publishedExists is true, treat as update
  2. Using GROQ filters in webhooks - The webhook filtering system allows you to create separate webhooks for drafts vs published documents using path filters like _id in path("drafts.*") to separate draft events from published events.

The key takeaway: patch operations fundamentally cannot create documents - they only modify existing ones. Creating a draft requires a create-type operation, which will always trigger a create event in webhooks.

A draft is just a document with an ID starting with
drafts.
, so you could make your patch set your ID as a draft?
Good call Kitty πŸ™Œ
Ah it looks like I can't use this as a workaround as I get this error using patch:

immutable attribute \"_id\" may not be modified
user C
user Y
I have the same problem, did you solve it?
user U
I didn't find anything for a work around so I just used post to create a new doc with the same draft ID which overwrites the original.

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?