How to handle homepage routing without slugs in Sanity with Next.js?

37 replies
Last updated: Jul 28, 2021
Guys, using slugs works but how do you do that for the homepage? I don’t want to define a slug for the homepage since it’s the root page.
I am using sections to create all the pages with renderSections in Next js.


AI Update

Perfect! This is a common pattern when building Next.js sites with Sanity. The solution is to use Next.js's optional catch-all route pattern with [[...slug]].js (note the double brackets).

Here's how to handle both your homepage and other pages in a single file:

Setup

Create a file at pages/[[...slug]].js (or app/[[...slug]]/page.js for App Router). The double brackets make the slug parameter optional, so it matches both:

  • / (homepage - slug is empty/undefined)
  • /about (slug is ['about'])
  • /blog/my-post (slug is ['blog', 'my-post'])

Implementation Example

export async function getStaticPaths() {
  const paths = await client.fetch(
    `*[_type == "page" && defined(slug.current)][].slug.current`
  );

  return {
    paths: [
      { params: { slug: [] } }, // This handles the homepage
      ...paths.map((slug) => ({ params: { slug: [slug] } }))
    ],
    fallback: 'blocking',
  };
}

export async function getStaticProps({ params }) {
  const slug = params?.slug?.join('/') || 'home'; // Use 'home' identifier for root
  
  const page = await client.fetch(
    `*[_type == "page" && slug.current == $slug][0]`,
    { slug }
  );

  return {
    props: { page },
    revalidate: 3600,
  };
}

export default function Page({ page }) {
  return renderSections(page.sections);
}

Schema Approach

In your Sanity schema, you can either:

  1. Create a special homepage document without a slug field (just query by _type == "homepage")
  2. Use a reserved slug like "home" or "index" that you don't display in the URL
  3. Use an empty string for the homepage slug

The optional catch-all route pattern is specifically designed for this use case - it matches the root path in addition to nested paths, unlike [...slug] which only matches nested paths.

This way, you maintain a clean URL structure without needing to define an actual slug for your homepage in Sanity, while still using the same renderSections approach across all pages.

Show original thread
37 replies
you can create a global settings doc with a Homepage reference and then use the structure builder to render it as a singleton
this is a powerful pattern that can be used in a bunch of creative ways
user G
is using it to swap out entire site themes like navigations, footers, etc
in the past i would default the site root to a slug of
home
or
homepage
but as Mike said, I am not following a wordpress settings style pattern, where you set the homepage in a global config, so any page in the system can be swapped as the hompage without having to worry about the
slug
How do you show the singleton on the front-end is there a example or anything? Because I love articles but this is way too long.
front-end of what?
sanity or the main site?
Example of like how to use it with Next JS f
you would just make an index.jsx file that overrides the [slug] file and select the specific singleton in the query
So I can keep the [slug].js inside the “pages” but the index should have the singleton only right?
// Next
import { useRouter } from "next/router";

// Queries
import { routesQuery } from "@lib/queries";

// Sanity
import { getClient } from "@lib/sanity.server";
import { PortableText, usePreviewSubscription } from "@lib/sanity";

// Helpers
import { formatDate } from "@lib/helpers";

// Components
import FeaturedImage from "@components/FeaturedImage";
import LandingPage from "@components/LandingPage";
import NextSeo from "@components/NextSeo";

const Page = ({ pageData, preview, slug }) => {
  const router = useRouter();

  const { data: { page = {} } = {} } = usePreviewSubscription(routesQuery, {
    params: { slug },
    initialData: pageData,
    enabled: preview || router.query.preview !== null,
  });

  const { body, featuredImage, publishedAt, title, author } = page;

  return (
    <>
      <NextSeo page={page} slug={slug} />
      <LandingPage page={page} />
      {featuredImage && <FeaturedImage featuredImage={featuredImage} />}
      {author && <p>Written by: {author.name}</p>}
      {publishedAt && <p>Publish date: {formatDate(publishedAt)}</p>}
      {title && <h1>{title}</h1>}
      {body && <PortableText blocks={body} />}
    </>
  );
};

export const getStaticProps = async ({ params = {}, preview = false }) => {
  const { slug } = params;
  const { page: pageData } = await getClient(preview).fetch(routesQuery, {
    slug,
  });

  return {
    props: { preview, pageData, slug },
  };
};

export const getStaticPaths = async () => {
  const routes = await getClient()
    .fetch(`*[_type == "route" && defined(slug.current)]{
    "params": {"slug": slug.current}
  }`);

  return {
    paths: routes || null,
    fallback: false,
  };
};

export default Page;

This my [slug].js btw for all other pages
you’d use essentially the same code just not fetcha ll pages, only the 1 you want
so you basically don’t need the getstaticpaths, and just need getstaticProps with a query to your home singleton
because you don’t need all the other
paths
in this case
I am using “routes” but instead of that I should use the
queries.homepage
?
rIght
Is there an example of index.js that I can check?
i don’t know what you mean by example, you have everything you need, just remove the getStaticPaths, and replace the routesQuery with a homeQuery
Ahhhhhh
where homeQuery is some singleton in your queries file
So everything else is oke just remove getStaticPaths and repalce routesQuery with Homequery
Got it
*[_type == 'page' && slug.current == 'home'][0]
type thing
exactly
Ahhh that’s why you create the singeleton 😄
for the homepage only
Great!
Maybe a stupid question
but Do you suggest like using “sections” for every single page?
i find it easier at the end of the day not to limit the client
Nice
because they always ask to add
xyz
to other places
So best practice is to let them select
Correct
Thanks boss

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?