How to retrieve Sanity data for meta tags across all Next.js pages?
Good question! You're right that this seems inefficient, but there are actually several approaches to handle site-wide metadata in Next.js with Sanity without duplicating queries on every page.
Modern Approach: Next.js App Router with Layouts
If you're using Next.js 13+ with the App Router, you can fetch global metadata in your root layout.tsx file. Unlike _app.tsx in the Pages Router, layouts in the App Router support data fetching directly:
// app/layout.tsx
import { client } from '@/sanity/lib/client'
async function getGlobalSettings() {
return await client.fetch(`*[_type == "siteSettings"][0]{
title,
description,
ogImage
}`)
}
export async function generateMetadata() {
const settings = await getGlobalSettings()
return {
title: settings.title,
description: settings.description,
openGraph: {
images: [settings.ogImage],
},
}
}
export default async function RootLayout({ children }) {
return (
<html>
<body>{children}</body>
</html>
)
}The App Router's React Server Components allow you to fetch data at the layout level, and you can use Next.js's generateMetadata function to set meta tags.
Pages Router Approach: Global Settings Pattern
If you're using the Pages Router (with _app.tsx and _document.tsx), you have a couple of options:
1. Create a "siteSettings" singleton document in Sanity and fetch it on each page, but pass it down through props to avoid re-querying:
// pages/index.tsx
export async function getStaticProps() {
const [pageData, globalSettings] = await Promise.all([
client.fetch(`*[_type == "page" && slug.current == "/"][0]`),
client.fetch(`*[_type == "siteSettings"][0]`)
])
return {
props: { pageData, globalSettings }
}
}2. Use React Context to share global settings across components after fetching them once per page load.
3. Fetch in _app.tsx using getInitialProps (though this disables automatic static optimization):
// pages/_app.tsx
MyApp.getInitialProps = async (appContext) => {
const globalSettings = await client.fetch(`*[_type == "siteSettings"][0]`)
return { globalSettings }
}This last approach works but has performance tradeoffs since it opts your entire app out of static generation.
Recommended Pattern
The cleanest approach is typically to:
- Create a
siteSettingssingleton document type in Sanity - Fetch it alongside your page-specific data in each page's
getStaticProps/getServerSideProps - Use Next.js's
next/headcomponent to set meta tags per page
While it means including the query on each page, Sanity's Content Lake is fast, and with proper caching/revalidation, the overhead is minimal. Plus, you maintain the benefits of static generation.
If you're starting fresh, I'd strongly recommend the App Router approach—it's much more ergonomic for this exact use case!
Show original thread14 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.