
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeBased on your query structure, you're likely seeing duplicate records because of how the spread operator (...page->) works with references and the raw perspective.
The issue is that when you query *[_type == "route"] and then spread properties from a referenced page document, if that page has both a published version and a draft version (even if you don't see drafts in the Studio), your query might be returning the same route multiple times - once for each state of the referenced page document.
Here's what's happening:
route documentspage and spreads its propertiesSolutions:
Option 1: Use the published perspective (recommended for production)
Add a perspective parameter to your API request to only return published documents:
// In your client configuration or query
const query = `*[_type == "route" && slug_custom_format.current != "index"]{
routeLabel,
"slug": slug_custom_format.current,
...page->{
_createdAt,
"pageId": _id,
_type,
_updatedAt,
}
} | order(_updatedAt desc)`
// Fetch with published perspective
client.fetch(query, {}, { perspective: 'published' })Option 2: Filter out draft references in your GROQ query
Explicitly exclude drafts in your query:
*[_type == "route" && slug_custom_format.current != "index" && !(_id in path("drafts.**"))]{
routeLabel,
"slug": slug_custom_format.current,
...page->{
_createdAt,
"pageId": _id,
_type,
_updatedAt,
}
} | order(_updatedAt desc)Option 3: Use defined() to ensure valid references
Sometimes references can cause duplication if they're undefined:
*[_type == "route" && slug_custom_format.current != "index" && defined(page)]{
routeLabel,
"slug": slug_custom_format.current,
...page->{
_createdAt,
"pageId": _id,
_type,
_updatedAt,
}
} | order(_updatedAt desc)The perspectives documentation explains how different perspectives affect query results. Even if you don't see drafts in the Studio, they may exist in your Content Lake, and the default raw perspective returns both states.
For production environments, always use the published perspective to avoid these kinds of duplicate results.
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store