Nextjs Dynamic nested paths

I have nested paths where I want a child page to be a dynamic page so that the content team can add it.

Structure:

Resources
  - Blog (dynamic page)
     - Blog pages (dynamic page)
  - Getting Started (dynamic page)
     - Pages (dynamic page)
- etc

How to set up files under app/ folder Page Type and link resolver all together?

Thank you in advance!

To achieve the dynamic page structure with Prismic and Next.js using the new app folder, you'll need to set up your routes dynamically while also configuring a link resolver to manage the relationships between pages and the dynamic content in Prismic.

Here’s a step-by-step guide to achieve this:

1. Setting up dynamic routes under the app directory

In the new Next.js 13 app folder structure, each folder corresponds to a route. Dynamic routes can be set using square brackets.

  • Dynamic Parent Page (e.g., blog)
    • Create the following structure inside your app directory:
      app/
        resources/
          blog/
            [uid]/
              page.js
            page.js
          getting-started/
            [uid]/
              page.js
            page.js
      
    • Each [uid] will correspond to the dynamic blog or getting started pages.

2. Creating the dynamic page for blog

In app/resources/blog/[uid]/page.js you can fetch the specific content from Prismic using the uid. Here’s an example:

// app/resources/blog/[uid]/page.js

import { createClient } from '../../../prismicio'; // Adjust path according to your prismic setup
import { PrismicRichText } from '@prismicio/react';

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

  // Fetch the document using the uid
  const blogPost = await client.getByUID('blog_post', params.uid);

  return (
    <div>
      <h1>{blogPost.data.title}</h1>
      <PrismicRichText field={blogPost.data.content} />
    </div>
  );
}

This page will dynamically load content based on the uid in the URL, using Prismic's getByUID.

3. Creating the dynamic parent page (e.g., blog)

In app/resources/blog/page.js you can list all the blog posts:

// app/resources/blog/page.js

import { createClient } from '../../../prismicio';
import Link from 'next/link';

export default async function BlogPage() {
  const client = createClient();

  // Fetch all blog posts
  const blogPosts = await client.getAllByType('blog_post');

  return (
    <div>
      <h1>Blog</h1>
      <ul>
        {blogPosts.map((post) => (
          <li key={post.id}>
            <Link href={`/resources/blog/${post.uid}`}>
              {post.data.title}
            </Link>
          </li>
        ))}
      </ul>
    </div>
  );
}

4. Set up the Link Resolver

Prismic’s link resolver allows you to manage links between documents. You can create a link-resolver.js to manage dynamic paths, especially for content types like blog_post or page.

// link-resolver.js

export const linkResolver = (doc) => {
  if (doc.type === 'blog_post') {
    return `/resources/blog/${doc.uid}`;
  }
  if (doc.type === 'getting_started') {
    return `/resources/getting-started/${doc.uid}`;
  }
  return '/';
};

5. Update Prismic Client to use Link Resolver

You’ll need to integrate the linkResolver into the Prismic client setup. Here’s how to do it inside prismicio.js (or wherever you’ve set up your Prismic client):

import * as prismic from '@prismicio/client';
import { linkResolver } from './link-resolver';

export const createClient = () => {
  const client = prismic.createClient(process.env.NEXT_PUBLIC_PRISMIC_ENDPOINT, {
    accessToken: process.env.PRISMIC_ACCESS_TOKEN,
  });

  // Add the link resolver
  client.linkResolver = linkResolver;

  return client;
};

6. Handling additional dynamic paths

For the getting-started and other nested sections, follow the same pattern as with blog. Adjust the content types and page structures accordingly.

For example, for a "Getting Started" dynamic page, create the structure:

app/
  resources/
    getting-started/
      [uid]/
        page.js
      page.js

Recap of Structure:

app/
  resources/
    blog/
      [uid]/    -> Dynamic blog post page
      page.js    -> Blog listing page
    getting-started/
      [uid]/    -> Dynamic getting-started page
      page.js    -> Getting started listing page

Each dynamic route will correspond to a page type in Prismic, and your link-resolver will generate the correct paths.

This structure allows your content team to manage both the parent and child dynamic pages easily within Prismic while maintaining clear routing in Next.js.

Thank you for the info.

How about the path in const routes: prismic.ClientConfig["routes"] function in prismicio.ts? Do you have examples?

Certainly! Here’s an example of a route resolver for Prismic in Next.js. The route resolver is slightly different from the link resolver, as it provides more control over URL generation, especially for nested or more complex URL structures.

Prismic Route Resolver Example

The routeResolver allows you to define more complex paths for your documents, such as when you have nested or hierarchical structures like you described (e.g., resources/blog/[slug]).

Here's an example of how you can set up a route resolver for your blog_post, getting_started, and other content types.

1. Create the Route Resolver

Create a new file called route-resolver.js in your project:

// route-resolver.js

export const routeResolver = {
  routes: [
    {
      type: 'blog_post',  // Prismic document type
      path: '/resources/blog/:uid',  // Route path in Next.js
    },
    {
      type: 'getting_started',  // Prismic document type
      path: '/resources/getting-started/:uid',  // Route path for getting started pages
    },
    {
      type: 'other_page_type',  // Example of another page type
      path: '/resources/:uid',  // Another path for dynamic content
    }
  ],
};

2. Update the Prismic Client to Use the Route Resolver

You need to modify your Prismic client configuration to use the routeResolver. Update your prismicio.js file (or wherever you've set up the Prismic client) to import and use the routeResolver.

// prismicio.js

import * as prismic from '@prismicio/client';
import { routeResolver } from './route-resolver';

export const createClient = () => {
  const client = prismic.createClient(process.env.NEXT_PUBLIC_PRISMIC_ENDPOINT, {
    accessToken: process.env.PRISMIC_ACCESS_TOKEN,
  });

  // Add the route resolver for more complex routing
  client.routes = routeResolver.routes;

  return client;
};

3. Using Route Resolver in Components

Once the route resolver is set up, you don’t need to manually build the paths using the document uid in your components. Instead, Prismic will automatically resolve the correct paths based on the routes you defined in the route resolver.

For example, when linking to a document, you can use the prismicH.asLink helper function, which will automatically use the correct path defined by the routeResolver.

Example in a component that lists blog posts:

import Link from 'next/link';
import { asLink } from '@prismicio/helpers';  // Helper from Prismic to resolve links

export default function BlogPostList({ blogPosts }) {
  return (
    <ul>
      {blogPosts.map((post) => (
        <li key={post.id}>
          {/* Use the asLink helper to automatically resolve the correct path */}
          <Link href={asLink(post)}>
            {post.data.title}
          </Link>
        </li>
      ))}
    </ul>
  );
}

In this case, the asLink(post) will resolve the link using the routeResolver, and for a blog_post document, it will generate a URL like /resources/blog/[uid].

4. Testing and Deployment

With the route resolver set up, you can now deploy your Next.js app and test the dynamic routing. When your content team creates a new blog_post or getting_started page in Prismic, it will automatically generate the correct URL using the route resolver and display the content based on the uid.

Summary

  1. Create the route-resolver.js file that defines how the routes are resolved based on the document type.
  2. Update the Prismic client to use the routeResolver.
  3. Use Prismic’s asLink or asLinkResolver functions in your components to automatically resolve URLs based on the defined routes.

This setup ensures that you can handle nested dynamic pages and have complete control over the paths, making it easy for your content team to add new pages.

Thank you, @Phil I will try to implement it and get back to you if I am stuck.

Can your team make a video tutorial on YouTube? This is a very complex build and I believe it will benefit most people.

1 Like

We already have documentation for this use case:

And our Youtube channel has lots of tutorials:

But I agree a video for directly this case in Next.js would be nice :slight_smile: