How to fetch draft versions of nested documents in Sanity GraphQL API?

16 replies
Last updated: Jan 27, 2026
Hey ๐Ÿ™‚ Quick simple question:We are using Sanity in next.js project, and we are fetching data from sanity using graphql apollo client. I'm implementing now live-preview. And there is an question.
I've implemented fetching drafts documents in qgl query by using is_draft filter:


  allPage(limit: 1, where: {_: { is_draft: $isDraft }, slug: { current: { eq: $slug } } }) {
But, i have also nested documents in Page document in form:


Page {
  slug,
  title,
  contentPlaceholder[] {
    Banner (Document)
    Section (Document)
    Cards (object)
    ...others (Documents and objects
  }
}
And if i am fetching all page data (with objects/documents in contentPaceholder field) All of these nested
objects are properly fetched (in drafts) but all of nested documents are fetched in last published version. I need to know how to get also drafts of nested documents using sanity graphql api ๐Ÿ™‚
AI Update

I understand your issue - when querying drafts in GraphQL, your top-level Page document returns the draft version, but referenced documents in the contentPlaceholder array are returning their published versions instead of drafts.

Unfortunately, GraphQL's is_draft filter doesn't automatically cascade to referenced documents. This is a known limitation of Sanity's GraphQL API. The is_draft filter only affects the root-level query, not the references within those documents.

Here are your options to solve this:

The modern approach is to use Perspectives with the GraphQL API. Instead of using the is_draft filter, add a perspective parameter to your GraphQL endpoint:

https://<projectId>.api.sanity.io/v2023-08-01/graphql/<dataset>/<tag>?perspective=previewDrafts

The previewDrafts perspective automatically overlays drafts on top of published documents throughout your entire query, including all nested references. This means:

  • If a draft exists, you get the draft
  • If no draft exists, you get the published version
  • This applies recursively to all referenced documents

In your Apollo Client setup:

const client = new ApolloClient({
  uri: `https://${projectId}.api.sanity.io/v2023-08-01/graphql/${dataset}/${tag}?perspective=${isDraft ? 'previewDrafts' : 'published'}`,
  // ... other config
});

Then simplify your query to:

allPage(limit: 1, where: { slug: { current: { eq: $slug } } }) {
  slug
  title
  contentPlaceholder {
    ... on Banner {
      # Banner fields - will be draft if available
    }
    ... on Section {
      # Section fields - will be draft if available
    }
  }
}

Note: You'll need to use GraphQL API version v2023-08-01 or later for Perspectives support.

2. Switch to GROQ (Alternative)

If Perspectives don't work for your setup, consider switching from GraphQL to GROQ queries with the HTTP API. GROQ gives you much more control over draft handling and can explicitly dereference draft versions of nested documents.

With GROQ, you can write custom logic to overlay drafts on references, which GraphQL doesn't support natively.

Why This Happens

GraphQL's is_draft filter is essentially a shorthand for filtering by _id prefix (drafts.), but it doesn't affect how references are resolved. When GraphQL resolves a reference field, it looks up the referenced document by its canonical ID (without the drafts. prefix), which always returns the published version.

Perspectives solve this by changing the query execution context at the API level, so all document resolutionsโ€”including referencesโ€”check for drafts first.

Show original thread
16 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?