Combining multiple GROQ queries in single Sanity client.fetch()

5 replies
Last updated: Jan 20, 2023
Can I combine two groq queries in one client.fetch?
And can client.fetch() and usePreview() use one of these combined queries?

Example:

const partnerQuery = groq`*[_type == "partner" && slug == "${slug}"][0]{name,slug,h1,h2,logo,"logoAspectRatio":logo.asset->metadata.dimensions.aspectRatio,undergrad_cosigned,undergrad_noncosigned,undergrad_outcomes,mba,medical,dental,law,grad}`;
and


const rateQuery = groq`*[_type == "rates" && name == "December"]`;
is it possible to combine these into one query so there's only one request? Or should they be kept separate?

I found in the docs that two queries can be combined in a "projection":

  const query = {
    partnerData: groq`*[_type == "partner" && slug == "${slug}"][0]{name,slug,h1,h2,logo,"logoAspectRatio":logo.asset->metadata.dimensions.aspectRatio,undergrad_cosigned,undergrad_noncosigned,undergrad_outcomes,mba,medical,dental,law,grad}`,
    rateData: groq`*[_type == "rates" && name == "December"]`,
  };
However,
client.fetch(query) wants the query parameter to be a string
and

usePreview only allows the second parameter to be a string


So would I need to have two fetches or usePreview (one for each query string)?:
const partnerData = usePreview(null, query.partnerData);
const rateData = usePreview(null, query.rateData);
AI Update

Yes, you can absolutely combine multiple GROQ queries into a single request! The key is understanding that the entire structure needs to be one GROQ query string that returns an object with multiple properties, not a JavaScript object containing separate query strings.

Based on the GROQ Query Cheat Sheet, here's the pattern for combining queries:

const combinedQuery = groq`{
  "partnerData": *[_type == "partner" && slug.current == "${slug}"][0]{
    name,
    slug,
    h1,
    h2,
    logo,
    "logoAspectRatio": logo.asset->metadata.dimensions.aspectRatio,
    undergrad_cosigned,
    undergrad_noncosigned,
    undergrad_outcomes,
    mba,
    medical,
    dental,
    law,
    grad
  },
  "rateData": *[_type == "rates" && name == "December"]
}`;

// Single fetch call
const data = await client.fetch(combinedQuery);

// Access the results
const partnerData = data.partnerData;
const rateData = data.rateData;

This works with both client.fetch() and usePreview() because you're passing a single query string that constructs an object containing the results of multiple queries.

Why this approach is better:

  • Single network request - reduces latency and overhead
  • Better performance - one round trip to the Content Lake
  • Atomic execution - both queries run together

The documentation specifically shows this pattern:

{
  'featuredMovie': *[_type == 'movie' && title == 'Alien'][0], 
  'scifiMovies': *[_type == 'movie' && 'sci-fi' in genres]
}

So your instinct was correct! Just remember: it's one complete GROQ query string that builds an object, not separate JavaScript strings.

Show original thread
5 replies
I think I just found the solution in your docs:

{
  "mainStory": *[_id == "story-1234"],
  "campaign": *[_id == "campaign-1234"],
  "topStories": *[_type == "story"] | order(publishAt desc) [0..10]
}
You should just be able to wrap the whole object in a string! Maybe try this:
  const query = groq`{
    partnerData: *[_type == "partner" && slug == "${slug}"][0]{name,slug,h1,h2,logo,"logoAspectRatio":logo.asset->metadata.dimensions.aspectRatio,undergrad_cosigned,undergrad_noncosigned,undergrad_outcomes,mba,medical,dental,law,grad},
    rateData: *[_type == "rates" && name == "December"],
  }`;
user M
I get:ClientError: string literal expected


    statusCode: 400,
    statusMessage: 'Bad Request'
  },
  statusCode: 400,
  responseBody: '{\n' +
    '  "error": {\n' +
    '    "description": "string literal expected",\n' +
    '    "type": "queryParseError"\n' +
    '  }\n' +
    '}',
  details: { description: 'string literal expected', type: 'queryParseError' },
I just passed the query into the fetch:

const sanityData = await sanityClient.fetch(query);
user M
Ok I think the groq was throwing it off
removing the groq worked:


  const query = `{
    "partnerData": *[_type == "partner" && slug == "${slug}"][0]{name,slug,h1,h2,logo,"logoAspectRatio":logo.asset->metadata.dimensions.aspectRatio,undergrad_cosigned,undergrad_noncosigned,undergrad_outcomes,mba,medical,dental,law,grad},
    "rateData": *[_type == "rates" && name == "December"],
  }`;
Thanks for your help on this
Glad you got it working!

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.

Was this answer helpful?