Querying nested draft documents in Sanity using GraphQL Apollo client
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:
1. Use Perspectives (Recommended)
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.
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.