Multiple document queries in Sanity GROQ with conditional object structure
I can see the issue with your query. The syntax you're using (_id == "frontpage" => { }) is conditional projection syntax, not a way to fetch multiple documents with different shapes. Let me explain the correct approach.
The Problem
Your query syntax is invalid because you're trying to use conditional projections incorrectly. The => operator in projections is meant to conditionally add fields to an object, not to create entirely different object structures based on filters.
The Solution
To fetch multiple documents with different structures in one query, you have a few options:
Option 1: Use Multiple Separate Queries (Recommended for Next.js)
The cleanest approach is to make two separate queries. In Next.js, you can fetch them in parallel:
// In your Next.js component or page
const [frontpage, siteSettings] = await Promise.all([
client.fetch(`*[_id == "frontpage"][0]{ _id, pageDescription, pageTitle, pageBuilder, mainImage }`),
client.fetch(`*[_id == "siteSettings"][0]{ title, description, primaryColor, secondaryColor, keywords }`)
])Option 2: Fetch Both and Transform Client-Side
Fetch both documents and project all fields, then handle the different structures in your application:
export const frontPageSettings = `
*[_id in ["frontpage", "siteSettings"]]{
_id,
// frontpage fields
pageDescription,
pageTitle,
pageBuilder,
mainImage,
// siteSettings fields
title,
description,
primaryColor,
secondaryColor,
keywords
}
`Then in your code, separate them:
const data = await client.fetch(frontPageSettings)
const frontpage = data.find(d => d._id === 'frontpage')
const siteSettings = data.find(d => d._id === 'siteSettings')Option 3: Use Conditional Projections (Correctly)
If you want to use conditional projections, the syntax needs to be different. The condition goes inside the projection to conditionally add fields:
export const frontPageSettings = `
*[_id in ["frontpage", "siteSettings"]]{
_id,
_id == "frontpage" => {
pageDescription,
pageTitle,
pageBuilder,
mainImage
},
_id == "siteSettings" => {
title,
description,
primaryColor,
secondaryColor,
keywords
}
}
`This will give you objects where frontpage documents have their specific fields and siteSettings documents have theirs, but they'll all have _id at the root level.
Why Your Original Query Failed
According to the GROQ pipeline components documentation, the condition => {} syntax expands the object on the right-hand side into the projection if the condition is true. It doesn't replace the entire projection - it adds to it. Your syntax was trying to use it as a filter replacement, which isn't valid.
Best Practice
For your use case with Next.js, Option 1 (separate queries with Promise.all) is the cleanest and most maintainable approach. It's explicit about what you're fetching, easier to type with TypeScript, and the performance difference is negligible since the queries run in parallel.
Show original thread7 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.