How to query Sanity documents to show only one item when both draft and published exist?
The issue you're experiencing is a common challenge when working with Sanity's draft system. When a document is published and then edited, you end up with two separate documents in the Content Lake: one with _id and another with drafts._id, which causes duplicates in your query results.
The solution is to use the previewDrafts perspective when configuring your Sanity client. This perspective automatically handles the draft/published overlay logic for you, returning only one document per item (prioritizing the draft version when both exist).
Using the previewDrafts Perspective
When you set up your Sanity client, specify the perspective:
import {createClient} from '@sanity/client'
const client = createClient({
projectId: 'your-project-id',
dataset: 'your-dataset',
useCdn: false, // Important: CDN doesn't support perspectives
apiVersion: '2024-01-01',
perspective: 'previewDrafts', // This does the magic!
})With previewDrafts, your queries will automatically return a single document per item, just like the Studio's document list pane. If a draft exists, you get the draft; if not, you get the published version.
Manual GROQ Approach
If you need more control or can't use perspectives, you can manually overlay drafts in your GROQ queries using scoring:
*[_type == 'post']
| score(_id in path("drafts.**"))
| order(_score desc, _id)
| {
...,
"isDraft": _id in path("drafts.**")
}This prioritizes draft documents by giving them a higher score. You can then group or deduplicate results in your application code.
Filtering Out Drafts in Production
For production environments where you only want published content, use the published perspective or filter drafts explicitly:
*[_type == 'post' && !(_id in path("drafts.**"))]Framework-Specific Solutions
If you're using Gatsby, the gatsby-source-sanity plugin has an overlayDrafts option that handles this automatically in development mode.
The key takeaway: perspectives (particularly previewDrafts) are Sanity's built-in solution for exactly this problem. They give you the same draft-overlay behavior that the Studio uses internally, so you get consistent results whether you're in the Studio UI or querying via the API. This is the recommended approach rather than manually filtering or merging drafts in your queries.
Show original thread1 reply
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.