How to handle multiple Sanity schemas in Next.js dynamic route [slug].js?
I'm not sure if my question is more related to Sanity or Nextjs dynamic routing but I'll ask anyway:
I have a parent page (
pages/numeros/index.js) that renders two types of content (listing posts w/ schema "numeros" and "archive"). When clicking into a numero or archive article, both schema should render into
numeros/[slug].jswith the same styling and formatting, since both schema contain the exact same data fields (for all intents and purposes they're the same thing, one is just reserved for their archived 'numeros' publications and as such is categorized differently on the
numeros/index.jspage).
I'm getting the numeros schema to render properly, but when I click into an archive post I get the following error, because I'm not sure how to handle the slug parameter in
getStaticPropsand
getStaticPathsfor both schema at once.
So the question is, how should I go about allowing for two data input streams for
[slug].js?
Here is my
getStaticPropsand
getStaticPathsin
[slug].js:
export async function getStaticProps({ params }) {
const footerLogos = await client.fetch(footerLogoQuery);
let slug;
const numero = await client.fetch(numeroQuery, {
slug: params.slug,
});
const readMoreData = await client.fetch(numeroReadMoreQuery, {
slug: params.slug,
});
return {
props: {
numero,
readMoreData,
footerLogos,
},
};
}
export async function getStaticPaths() {
const paths = await client.fetch(
groq`*[_type == "numero" && defined(slug.current)][].slug.current`
);
return {
paths: paths.map((slug) => ({ params: { slug } })),
fallback: true,
};
}getStaticPropsfor instance, as I would have two declarations of
numero.
const numero = await client.fetch(archiveListQuery, {
slug: params.slug,
});The solution is to query both content types together using GROQ's in operator. Since your "numero" and "archive" schemas have the same fields, you can treat them as a single content stream.
Update your getStaticPaths:
export async function getStaticPaths() {
const paths = await client.fetch(
groq`*[_type in ["numero", "archive"] && defined(slug.current)][].slug.current`
);
return {
paths: paths.map((slug) => ({ params: { slug } })),
fallback: true,
};
}Update your getStaticProps:
export async function getStaticProps({ params }) {
const footerLogos = await client.fetch(footerLogoQuery);
// Query both types at once - whichever matches the slug will be returned
const numero = await client.fetch(
groq`*[_type in ["numero", "archive"] && slug.current == $slug][0]`,
{ slug: params.slug }
);
// Handle case where no document is found
if (!numero) {
return {
notFound: true,
};
}
const readMoreData = await client.fetch(numeroReadMoreQuery, {
slug: params.slug,
});
return {
props: {
numero,
readMoreData,
footerLogos,
},
};
}The key is _type in ["numero", "archive"] in your GROQ query. This filters for documents that match either type, so you get a single result regardless of which schema the slug belongs to.
Since both schemas have identical fields, the returned document works the same way in your component. If you ever need to know which type was returned (for conditional logic or analytics), you can check numero._type in your component.
Make sure your numeroReadMoreQuery also handles both types if it filters by _type - just apply the same _type in ["numero", "archive"] pattern there.
Show original thread6 replies
Was this answer helpful?
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.