Handling navigation for singletons in Sanity.io without slugs

5 replies
Last updated: Apr 21, 2023
I have a singleton Homepage and multiple Page type for all other pages. Each page has a slug which works great when creating an navigation array for the website. But my biggest problem is how can I set a menu Title + Link for the singleton using a slug? Same story for the Blog overview this is a singleton type too and have no slug.
I was thinking to have a slug field with a default fixed slug like "frontpage" and set it read only, so this way I can select it from a reference?

Any tips please
🙂 I am stuck at this pretty confusing.. on how to deal with this.
Home & Blog => Singleton no slugs.
Pages: About, Contact, Team etc with slugs.
AI Update

Your approach of adding a slug field with a fixed default value to singletons is actually a solid pattern! This is a common and practical solution that many Sanity developers use. Let me break down a few approaches:

Add a slug field to your singleton documents with a fixed, read-only value:

// homepage.js (singleton)
{
  name: 'homepage',
  type: 'document',
  fields: [
    {
      name: 'slug',
      type: 'slug',
      initialValue: {
        current: '/'
      },
      readOnly: true,
      hidden: true // Optional: hide it from editors since it never changes
    },
    // ... other fields
  ]
}

// blogOverview.js (singleton)
{
  name: 'blogOverview',
  type: 'document',
  fields: [
    {
      name: 'slug',
      type: 'slug',
      initialValue: {
        current: '/blog'
      },
      readOnly: true,
      hidden: true
    },
    // ... other fields
  ]
}

This way, when you create navigation arrays using references, all documents (singletons and regular pages) have a consistent slug field you can query.

Approach 2: Virtual Slug in Your Navigation Query

Instead of storing slugs on singletons, handle them in your GROQ query:

*[_type == "navigation"][0] {
  items[] {
    title,
    "slug": select(
      reference->_type == "homepage" => "/",
      reference->_type == "blogOverview" => "/blog",
      reference->slug.current
    ),
    reference-> {
      _type,
      title
    }
  }
}

This keeps your schema cleaner but puts the logic in your queries.

Approach 3: Custom Navigation Object

Create a dedicated navigation schema where you can set custom paths for singletons:

{
  name: 'navigation',
  type: 'document',
  fields: [
    {
      name: 'items',
      type: 'array',
      of: [{
        type: 'object',
        fields: [
          {name: 'title', type: 'string'},
          {name: 'reference', type: 'reference', to: [{type: 'homepage'}, {type: 'page'}, {type: 'blogOverview'}]},
          {
            name: 'customPath',
            type: 'string',
            description: 'Override path for singletons (e.g., "/" for homepage)'
          }
        ]
      }]
    }
  ]
}

Then in your frontend, use customPath if it exists, otherwise fall back to reference.slug.current.

My Recommendation

Go with Approach 1 (fixed slugs on singletons). It's the most straightforward and keeps your data consistent. The slug field type supports this perfectly with initialValue and readOnly options. This pattern allows you to:

  • Use the same reference-based navigation structure everywhere
  • Query all navigable documents consistently
  • Keep your frontend logic simple
  • Still maintain the singleton pattern for content management

The slight "weirdness" of having a slug on a singleton is worth the consistency it brings to your navigation system. Many Sanity projects use this exact pattern successfully!

Hi User, and i had been looking over your original post, trying to guess just what you had and knew.
First, the 'blog' entry does have a slug, 'blog', and should fit in an Internal Link item which I think you have, in at least the style of this out-of-date and overly compicated description of such a Nav scheme.

It's typical in other programming to do just as you suggest, have a known alias, 'home', etc. as the slug for a root '/' page -- think you're on the right track there.

What complicates the picture is just what the Studio might do with that alias 'home'. There was never the promised Part 3 for that article, so we don't know how the Nav menu was ever linked into Studio operation.

It's not an area I've gotten into yet in such a way, but I suspect the menu operation gets defined via the Structure Builder, doc'd beginning here:
https://www.sanity.io/docs/structure-builder-introduction
One thing that might simplify I do know, that you can often isolate to the structure area you want to affect, and just write the code for that alone, leaving the rest to default.

As it sounds like you inherited this project, you might find such things already done, in or imported into your Studio's sanity.config.js/ts file.

The shortcut I mention is demonstrated here, at this point in the overview article for adding a preview panel alongside the document editor:
https://www.sanity.io/docs/structure-builder-introduction#b4971351a508
Hope this gives you enough of a leg up to solve this, especially as it sounds you have a very suitable idea...
user Q
Thanks! So, I have a navigation array with internal & external links. Internal is a reference to Page & Post and external is a free to use slug input to link to external websites etc.
Each Page & Post has a slug which is required this way I can link it and get the
slug.current
(slug) of that specific document.
Now, I have created 2 singletons Blog and Home because I don't want clients to create a Page named "blog" and by accident remove it. I need the singleton Blog to display all the posts.

The homepage singleton is for the index (page) route inside my Next 13 application.

Both singletons have no slug because I am fetching the data of each inside the root index for both routes.

The problem is because I have no slug on these singletons there is no way to create a reference or connection.

So for now both have slug fields which are "ReadOnly" and for the homepage I am checking if slug is equal to rewrite to "/" else return current slug same thing for the blog.

have additional array navigation item named Singleton Link which links to Home or Blog and returns the slug of each singleton. Otherwise I can't create my navigation.

Can't come up with a better solution here.

Everything else is straight to the point, each page has a pageBuilder of sections to create and order the page a client wants to. The blog also has the pageBuilder but the Archive Overview Query of posts is always available.
That sounds workable, and...if it works for you 🙂
I think that when we operate within a complex system like Sanity, and can't get at operations to alter or configure them, it's an entirely sensible thing to make local workarounds, as it feels you have done.

Take satisfaction in it, and enjoy your week-end, User!

Best,
User
Thank you very much User. I used to overcomplicate things and trying always to have PERFECT code and clean as possible. But I realised, the more I focus on that the less my I use my brains to think outside of the box and focus on getting things done instead of focussing on getting things to look perfect. For now it works maybe in a couple of days there will be a better solution from my side for it.
Appreciating Italian design as I do, this feels a way to keep ît to human scale, as one may think on a Friday :)

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?