How to create a dynamic homepage reference in Sanity that won't break if slug changes?

3 replies
Last updated: Jun 29, 2023
I am fetching my homepage based on it's slug "frontpage" which is defined in the slug input value. But my main concern and issue is a client changes this slug, the frontpage / homepage won't work anymore. Is there anything I can do or any advice on how to define the homepage and use this defined value dynamic slug instead?
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?
AI Update

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.

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:

  1. Slug-independent - Clients can change slugs freely
  2. User-friendly - Editors can easily change which page is the homepage through the UI
  3. Flexible - Easy to add other site-wide settings later
  4. 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 thread
3 replies
Hi (Removed Name),
You could fetch your homepage based on
_id
, which can't be changed like the slug can. The
_id
is randomly generated, but you can customize it. Here's a video that demonstrates how to do that.
user E
thank you!
I've got this setup in my Site Settings singleton and it seems to be working quite well. You have to know how to query it from the root index route in your frontend, but that'll vary by framework. I'm using Remix for what it's worth. I have a hidden flag of isFrontpage on the page document itself. And when I publish my settings (using a custom publish action), it updates (or patches) whatever page reference I've set that field to. In this case, Home. And then in my preview list for pages, I can use that hidden isFrontpage field to add a (Frontpage) label to the page that is the front-page. This way, you could change the front page from the settings to whatever page you want.

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?