How to create sectional routes in Prismic on the NextJS App Router

I'm writing this post because the documentation at Route Resolver - Documentation - Prismic is missing critical information to make this work.

Scenario:
You have a website that is too complex for a flat file structure and you want to route pages to subsections like:
/about/our-mission
/membership/benefits

...but you don't want ot set up and manage a different post type for every section of the stie. You just need an URL taxonomy that matches your nav (don't get me into the complexities of creating a megamenu with relational slices just yet).

You think /[uid]/page.tsx should work just fine and so do I -- and I can almost give it to you. almost

According to the docs it looks like you just go into prismicio.tsx and set your routes...

const routes: prismic.ClientConfig["routes"] = [
  {
    type: "home",
    path: "/",
  },
 {
    type: 'page',
    resolvers: {
      about: 'about',
      members: 'members',
    },
];`

and call it a day... right?

Well not exactly.

Steps to actually make this work:

  1. Create a custom post type. I called mine "route"
  2. Create a standard text box called something like "Section Title"
  3. Move it above the UID static field. Trust me on this (it auto-populates the slug) if it's not there
  4. Return to your page type "page" (or whatever we are routing off of)
  5. Add a content relationship - I called mine "URL Route" (url_route)
  6. Push your changes
  7. Open the builder
  8. Create your route titles (in our case About and Membership - the pages are "our-mission" and "benefits" respectively)
  9. Open the pages you want routed and add content relationships to those titles
  10. Now edit prismicio.ts in the root of your app

Your routes should look like this if you are using my taxonomy, YMMV with your own

  {
    type: "home",
    path: "/",
  },
  {
    type: "route",
    path: "/:uid",  // This will handle sections like /about, /services, etc.
  },
  {
    type: "page",
    resolvers: {
      route: "url_route",  // Resolving the section relationship
    },
    path: "/:route/:uid",  // This will generate URLs like /about/mission
  },
];
  1. Create a folder called [...slug] in /app or /app/src depending on your Next configuration. Why, you ask? Well that's a good question because it breaks with the Prismic naming convention of [uid] but this is a NextJS thing that is required if you want dynamic routes to work. Without it you can console log the page object, see it's generating the correct URL, and yet Next the honeybadger won't give a f***. This is how you do it in Next.
  2. Add a functional page.tsx file inside of [...slug]. This is more complex than you think because there isn't a matching route inside of the builder so your slice zone will error out. You'll also be throwing a duplicate routes warning on load. Saving you the headache - solve it like this, assuming you are routing off of the "page" post type. If you're doing something else you'll need to adjust your naming convention.
import { notFound } from "next/navigation"
import { SliceZone } from "@prismicio/react"

import { createClient } from "@/prismicio"
import { components } from "@/slices"

export default async function Page({ params }) {
  const client = createClient()

  const page = await client.getByUID("page", params.slug.at(-1) || "home")
    .catch(() => notFound())

  return <SliceZone slices={page.data.slices} components={components} />
}

export async function generateMetadata({ params }) {
  const client = createClient()

  const page = await client.getByUID("page", params.slug.at(-1) || "home")
    .catch(() => notFound())

  return {
    title: page.data.meta_title,
    description: page.data.meta_description,
  }
}

export async function generateStaticParams() {
  const client = createClient()

  const pages = await client.getAllByType("page")

  return pages.map((page) => {
    return { slug: page.url.split("/").slice(1) }
  })
}
  1. Stop your Next server
  2. Clear your .next cache for good measure - rm -rf .next
  3. Run your NextJS server - npm run dev

Congratulations, your custom route types now control your URL structure. Consider giving them friendly names and tags and, like me, wait eagerly for file grouping to arrive on a future update.

Note to Prismic: please automate this in slice machine. It's a lot of abstraction for the average person to grok.