How to resolve references in GROQ queries for page builder components
Perfect! The article actually covers your exact use case. When you have an array with mixed content (some references, some inline objects), you can use the coalesce() function with the @ operator.
Here's the solution:
*[_type == "page" && pageMetadata.slug == 'test'][0]{
pageBuilderComponents[]{
...coalesce(@->, @)
}
}How this works:
@represents the current element in the array@->attempts to dereference the current element (only works if it's a reference)coalesce(@->, @)tries to resolve as a reference first (@->), and if that returns null (because it's not a reference), it falls back to the original object (@)- The spread operator
...expands all the fields from whichever resultcoalescereturns
This pattern is mentioned in the Reference Access Operator documentation as the recommended approach for handling mixed content types in arrays.
Alternative approach if you want more explicit control:
*[_type == "page" && pageMetadata.slug == 'test'][0]{
pageBuilderComponents[]{
_type,
select(
defined(_ref) => @->,
!defined(_ref) => @
)
}
}This uses select() to check if the element has a _ref field (indicating it's a reference) and conditionally resolves it. However, the coalesce approach is cleaner and more idiomatic for this use case.
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.