How to patch Sanity draft documents when syncing from external API?

13 replies
Last updated: Nov 30, 2025
Hi guys, I something that I'm struggling to understand, I think it's more of a conceptual thing with how Sanity treats drafts. I'm trying to sync documents from an external API, and it's working great using a Netlify function. In this case it's categories that come from a custom portal that the business uses, and will each sync over to sanity as documents whenever they are created / edited / deleted. I've got this working and it's super quick and great. However, I'm adding a few extra fields to each document within Sanity, for example a category description. I've noticed that if I have unpublished changes from within Sanity on a category, and I make changes in the external portal, it doesn't sync. I believe this is to do with the
_id
changing to
drafts.xxxxx
when there's a draft, so the patch I'm trying to run on the document doesn't do anything, as it's being patched to the regular
_id
, not the temporary draft
_id
. My question is, what's the best way to patch to a draft? Is it possible? I've looked high and low through the docs but I just can't see it mentioned. Below is the sync function for reference. Thanks very much for taking the time to read this.
AI Update

Great question! You've correctly identified the issue - when a document has unpublished changes in Sanity, it exists as a draft with the drafts. prefix, so patching the regular _id won't affect it.

The solution is actually straightforward: you need to patch both the published document AND the draft (if it exists). Here's how to handle this in your sync function:

The Best Approach

When syncing from an external system, you should check if a draft exists and patch both IDs. Here's a pattern you can use:

// Patch both the published and draft versions
const documentId = 'your-document-id'
const patches = [
  client.patch(documentId).set({ /* your changes */ }),
  client.patch(`drafts.${documentId}`).set({ /* your changes */ })
]

// Execute both patches - if the draft doesn't exist, that patch will simply have no effect
await Promise.all(patches.map(patch => patch.commit().catch(() => null)))

Alternative: Use Patch by Query

You can also use patch by query to target both versions at once:

await client
  .patch({
    query: '*[_id in [$id, $draftId]]',
    params: {
      id: documentId,
      draftId: `drafts.${documentId}`
    }
  })
  .set({ /* your changes */ })
  .commit()

This approach is cleaner because it patches whichever version(s) exist in a single operation.

Important Considerations

  1. Draft fields you added in Sanity - If editors have added content to those extra fields (like your category description) in the draft, make sure your sync function only updates the fields coming from the external system. Use .set() for specific fields rather than .createOrReplace() which would wipe out the entire document.

  2. Validation - When using the Mutation API directly, server-side validation doesn't enforce Studio schema rules, so make sure your sync function respects the schema.

  3. Consider Sanity Functions - Since you're currently using a Netlify function, you might want to consider migrating to Sanity Functions which are serverless compute that runs within Sanity. They offer native integration, automatic scaling, and better security without needing external hosting. You could set up event handlers to react to changes in your external portal.

The key insight is that in Sanity's draft system, drafts and published documents are separate entities that can coexist, so external syncs need to update both to ensure consistency regardless of the document's state in Studio.

Show original thread
13 replies

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?