Define Paths

Defining dynamic routes is an essential part of building a website with a CMS. As your content creators begin to add their new pages, the web app will need to create URL paths to hit those pages. That’s where routing comes in.

To define routes for Prismic, you will create a routes option in your client config, which describes the routing structure of your Next.js application. Here's how to define fixed paths, dynamic paths, and nested paths with the routes option:

Fixed paths

If you have a fixed page, like pages/about.js, you don’t need getStaticParams(). Next.js already knows the route and the content for the route. However, you still need to define the route in your Prismic routes option, to enable internal linking.

This is a route in the routes option for the About page:

prismicio.js
Copy
const routes = [
  {
    type: 'page',
    uid: 'about',
    path: '/about',
  },
]

Dynamic paths

In Next.js’s filesystem-based routing, dynamic path segments are defined inside square brackets: pages/[uid].js or app/[uid]/page.js. This route handles any URL with a single path segment, such as /apples or /carrots. The square brackets around [uid] act as a wildcard.

Next.js’s static generation will pre-render all the pages in your website to optimize page speed. To do so, Next.js must know what pages to render. In the Page Router, getStaticPaths() tells Next.js what pages to render for a dynamic route, such as pages/[uid].js.

Next.js’ getStaticPaths() function is called once when your project is built. It will need to know all the possible routes for a page, so using the Prismic client’s getAllByType() query and the asLink() function, we can quickly get all the documents of a page type and return that information from the Prismic API to build those paths.

Here’s an example:

src/pages/[uid].js
Copy
import * as prismic from '@prismicio/client'
import { createClient } from '../prismicio'

// Fetch content from prismic
export async function getStaticProps({ params, previewData }) {
  const client = createClient({ previewData })

  const page = await client.getByUID('page', params.uid)

  return {
    props: { page },
  }
}

// Define Paths
export async function getStaticPaths() {
  const client = createClient()

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

  return {
    paths: pages.map((page) => prismic.asLink(page)),
    fallback: true,
  }
}

Here, getStaticPaths() tells Next.js to render a page for every page document from Prismic. In the setup step, you defined a route resolver (the routes option). Next.js will generate a route for every document specified with your route resolver.

Defining dynamic paths in the App Router works similarly. generateStaticParams() tells Next.js the values of the dynamic segments in the route, such as uid in the route /[uid].

src/app/[uid]/page.js
Copy
import { createClient } from '@/prismicio'
import { notFound } from 'next/navigation'

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

  const page = await client
    .getByUID("page", params.uid)
    .catch(() => notFound())

  return <h1>{page.uid}</h1>
}

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

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

  return pages.map((page) => {
    return { uid: page.uid }
  })
}

Here is the routes option for the above example:

prismicio.js
Copy
const routes = [
  {
    type: 'page',
    path: '/:uid',
  },
]

Nested paths

Next.js and Prismic both support nested paths. In Next.js, this is accomplished with filesystem-based routing. In Prismic, this is accomplished with the route resolver.

For example, you could have the file pages/[category]/[uid].js, which would return a file for the /*/* URL. That might render a page for /clothing/t-shirt or /dogs/doberman. Here’s how that looks in Next.js:

  • App Router
  • Pages Router
App Router
src/app/[category]/[uid]/page.js
Copy
import { createClient } from '@/prismicio'
import { notFound } from 'next/navigation'

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

  const page = await client
    .getByUID("page", params.uid)
    .catch(() => notFound())

  return <h1>{page.uid}</h1>
}

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

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

  return pages.map((page) => {
    return {
      category: page.data.category.uid,
      uid: page.uid,
    }
  })
}
Pages Router
src/pages/[category]/[uid].js
Copy
import * as prismic from '@prismicio/client'
import { createClient } from '../prismicio'

// Fetch content from prismic
export async function getStaticProps({ params, previewData }) {
  const client = createClient({ previewData })

  const page = await client.getByUID('page', params.uid)

  return {
    props: {
      slices: page.data.body,
    },
  }
}

// Define Paths
export async function getStaticPaths() {
  const client = createClient()

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

  return {
    paths: pages.map((page) => prismic.asLink(page)),
    fallback: true,
  }
}

Here is the routes option for the above example:

prismicio.js
Copy
const routes = [
  {
    type: 'page',
    resolvers: {
      category: 'category',
    },
    path: '/:category/:uid',
  },
]

For more information about nested paths including how to model them, see the Route Resolver article.

Catch-all paths

Beyond using directories, Next.js also has a catch-all routes option, which looks like pages/[[...uid]].js. This would render a page for /*, /*/*, /*/*/*, etc. So, you could render a page for both /dogs/doberman and /poodle. Here’s how that looks in Next.js:

  • App Router
  • Pages Router
App Router
src/app/[[...pagePath]]/page.js
Copy
import { createClient } from '@/prismicio';
import { notFound } from "next/navigation";

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

  /*
   * `params.uid` contains an array of each part of the URL separated by a `/`.
   * In this example, the last part is the document's UID.
   */
  const uid = params.pagePath[params.pagePath.length - 1]

  const page = await client
    .getByUID('page', uid)
    .catch(() => notFound())

  return <h1>{page.uid}</h1>
}

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

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

  return pages.map((page) => {
    return { pagePath: page.url.split('/').filter(Boolean) }
  })
}
Pages Router
src/pages/[[...uid]].js
Copy
import * as prismic from '@prismicio/client'
import { createClient } from '../prismicio'

// Fetch content from prismic
export async function getStaticProps({ params, previewData }) {
  const client = createClient({ previewData })

  /*
   * `params.uid` contains an array of each part of the URL separated by a `/`.
   * In this example, the last part is the document's UID.
   */
  const uid = params.uid[params.uid.length - 1]

  const page = await client.getByUID('page', uid)

  return {
    props: {
      slices: page.data.body,
    },
  }
}

// Define Paths
export async function getStaticPaths() {
  const client = createClient()

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

  return {
    paths: pages.map((page) => prismic.asLink(page)),
    fallback: true,
  }
}

Prismic’s route resolver allows for optional segments. The following routes option will conditionally render the :category segment only if it is present, otherwise omitting it:

prismicio.js
Copy
const routes = [
  {
    type: 'page',
    resolvers: {
      category: 'category',
    },
    path: '/:category?/:uid',
  },
]

Summary

  • Your routes option should reflect the folder structure of your Next.js project.
  • Next.js and Prismic work together to offer advanced routing with conditional segments, internationalization, and nested routes.
  • When you have the routes option implemented, getStaticPaths() should look almost the same for every page file.

Was this article helpful?
Not really
Yes, Thanks

Can't find what you're looking for? Spot an error in the documentation? Get in touch with us on our Community Forum or using the feedback form above.