How to create a dynamic homepage reference in Sanity that won't break if slug changes?
I have a settings page I was thinking having a reference to a page where you define the homepage and based on that page to fetch the data on the index page?
Are there any smarter or cleaner ways of doing this?
You're absolutely right to be concerned about clients changing slugs and breaking your homepage! This is a common problem, and there are several good solutions. Your idea of using a settings page with a reference is actually one of the best approaches.
Recommended Solution: Singleton Settings with Reference
The cleanest way to handle this is to create a singleton settings document that stores a reference to your homepage. Here's how:
1. Create a Settings Schema
First, create a singleton siteSettings document type as described in this guide on creating singleton documents:
// schemas/siteSettings.ts
import {defineField, defineType} from 'sanity'
export default defineType({
name: 'siteSettings',
title: 'Site Settings',
type: 'document',
fields: [
defineField({
name: 'homepage',
title: 'Homepage',
type: 'reference',
to: [{type: 'page'}],
validation: Rule => Rule.required()
}),
// other settings...
]
})2. Set Up as Singleton in Studio
Configure your Structure Builder to make this a singleton:
// structure.ts
export const myStructure = (S) =>
S.list()
.title('Content')
.items([
S.listItem()
.title('Site Settings')
.child(
S.document()
.schemaType('siteSettings')
.documentId('siteSettings')
),
...S.documentTypeListItems().filter(
listItem => !['siteSettings'].includes(listItem.getId())
)
])3. Fetch Homepage in Your Frontend
Then in your Next.js (or other framework) index page:
// app/page.tsx
const query = `*[_id == "siteSettings"][0].homepage->{
title,
content,
// all your page fields
}`
const homepage = await client.fetch(query)Alternative Approaches
Option 2: Document-Level Flag
Add a boolean field isHomepage to your page schema:
defineField({
name: 'isHomepage',
title: 'Set as Homepage',
type: 'boolean',
validation: Rule => Rule.custom((value, context) => {
// You could add validation to ensure only one page is marked as homepage
return true
})
})Then query: *[_type == "page" && isHomepage == true][0]
Option 3: Fixed Document ID
Instead of using slugs, create your homepage with a fixed _id:
// In your initial value template or manually
{
_id: 'homepage',
_type: 'page',
title: 'Home',
// ... other fields
}Then query: *[_id == "homepage"][0]
Why the Settings Reference is Best
The singleton settings with reference approach is the cleanest because:
- ✅ Slug-independent - Clients can change slugs freely
- ✅ User-friendly - Editors can easily change which page is the homepage through the UI
- ✅ Flexible - Easy to add other site-wide settings later
- ✅ Type-safe - References are validated by Sanity
The only downside is it requires an extra query hop, but Sanity's reference resolution makes this very efficient, and you can use reference projections (the -> operator) to resolve it in a single query as shown above.
Show original thread3 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.