Next.js with previews and Draft Mode

Hey everyone,

I'm Angelo, one of Prismic's engineers working on our Next.js integration.

We are working toward full support for Prismic projects built using the new App Router. Preview support is the last major piece we are working on before we can fully recommend the App Router.

We are close to a solution you can use today, but it has some caveats, such as only working with dynamic rendering, where we would normally recommend using static rendering. You can learn the differences between dynamic and static rendering in the Next.js docs. We will be publishing documentation on setting up an experimental version of preview support soon.

We opened a feature request for Next.js that would allow us to implement Prismic previews using static rendering, which would allow for better performance over the experimental preview support. You can see the request here:

You can share your support for the feature request by giving it an upvote and :+1:.

If you have any questions about the status of Next.js and Prismic previews in the App Router, please leave them here. Thank you for your support!

6 Likes

Hey @angeloashmore, this is the last piece missing for my team to adopt the new App router. We currently have a PR on hold due to the missing preview feature. Could you provide a bit more guidance on how to use the preview forcing the dynamic mode? I'd tried to add it to the root layout but it isn't working, even for localhost previews.

/app/layout.tsx

export const dynamic = 'force-dynamic'

...
1 Like

Hey @gabriel,

I'm glad to hear you have everything else working in the App Router! :slight_smile:

We don't have the updated Preview + App Router docs published yet, but I can share fragments of it here.

The Next.js team is working on the proposal described in the discussion above which will ultimately replace the strategy explained below. However, much of the implementation will use the same APIs (<PrismicPreview>, enableAutoPreviews(), etc.).

When an updated version of Next.js is released with Draft Mode + cookies() support, we will post an updated guide with the correct usage.

Until then, here's how you can use previews today with the App Router and dynamic rendering (content taken from an draft version of an upcoming tutorial).

If you have any questions, please leave them here. Thanks! :smile:




Set up createClient()

Ensure your createClient() function uses the following fetchOptions and calls enableAutoPreviews().

// src/prismicio.js

  import * as prismic from '@prismicio/client'
  import * as prismicNext from '@prismicio/next'

  export const createClient = (config = {}) => {
    const client = prismic.createClient(repositoryName, {
+     fetchOptions: {
+       cache: process.env.NODE_ENV === "production" ? "force-cache" : "no-store",
+       next: { tags: ['prismic'] },
+     },
      ...config,
    })

+   prismicNext.enableAutoPreviews({ client })

    return client
  }

Set up previews

Prismic Previews in the App Router are currently experimental and only supported using dynamic rendering. All Prismic API requests are cached at request time, resulting in performance similar to static rendering.

If you prefer static rendering, remove Prismic Preview support or use the Pages Router.

Add <PrismicPreview> to your layout

Prismic Previews require the Prismic Toolbar and a framework integration to work. @prismicio/next provides all the code you need in a simple <PrismicPreview> component.

Add the component to your global layout in src/app/layout.tsx.

// src/app/layout.tsx

+ import { PrismicPreview } from "@prismicio/next";

+ import { repositoryName } from "@/prismicio";

  export default async function RootLayout({
    children,
  }: {
    children: React.ReactNode;
  }) {
    return (
      <html lang="en">
        <body>
          {children}
+         <PrismicPreview repositoryName={repositoryName} />
        </body>
      </html>
    );
  }

Create a /preview Route Handler

A small bridge is needed between Prismic and your Next.js website to support previews. You can connect the two by creating a Route Handler, which will redirect content writers from Prismic to their previewed document’s webpage.

  1. Create a directory named preview within the src/app directory.
  2. Within the src/app/preview directory, create a file named route.ts and paste in the code below.
// src/app/preview/route.ts

import { NextRequest } from "next/server";
import { redirectToPreviewURL } from "@prismicio/next";

import { createClient } from "@/prismicio";

export async function GET(request: NextRequest) {
  const client = createClient();

  await redirectToPreviewURL({ client, request });
}

Set up previews in Prismic

You’ll need to tell Prismic your app’s URL in order to preview content.

  1. Go to your Prismic repository.
  2. Open the settings page using the gear icon in the bottom left corner.
  3. Select Previews in the sidebar.
  4. Fill out the fields with these values:
    Site Name: Development
    Domain: http://localhost:3000
    Preview Route: /preview
  5. Click “Create my Preview”

Add other preview endpoints as needed, such as your production URL.

Set up On-demand Revalidation

Your app is configured to cache all Prismic queries indefinitely for the best performance. However, you’ll want to fetch new content after you publish documents in Prismic.

In this last step of this tutorial, you’ll set up On-demand Revalidation to do exactly that: Prismic will be configured to call one of your app’s endpoints to clear Next.js’ network cache upon content changes.

On-demand Revalidation won’t have an effect until you deploy your app. If you don’t plan to deploy your app, you can skip this section.

  1. Create a directory named revalidate within the src/app directory.
  2. Within the src/app/revalidate directory, create a file named route.ts and paste in the code below.
// src/app/revalidate/route.ts

import { revalidateTag } from 'next/cache'
import { NextResponse } from 'next/server'

export async function POST() {
  revalidateTag('prismic')

  return NextResponse.json({ revalidated: true, now: Date.now() })
}

Set up On-demand Revalidation in Prismic

Once your app is deployed and has a public URL, you’ll need to create a Prismic webhook pointed to the /revalidate endpoint.

  1. Go to your Prismic repository.
  2. Open the settings page using the gear icon in the bottom left corner.
  3. Select Webhooks in the sidebar.
  4. Fill out the fields with these values:
    Name of the Webhook: Next.js On-Demand Revalidation
    URL: Your app’s deployed URL + /revalidate (example: https://example.com/revalidate)
    Triggers: Only check “A document is published” and “A document is unpublished”
  5. Click “Add this webhook”.

You can test everything is working by publishing an edit to a document and viewing its page on your deployed website. You should see your changes reflected practically immediately after publishing.

3 Likes

Oh great! That will be super helpful!

Is there a way we can use the preview mode and on-demand revalidation at the same time with both /pages and /app directories?

Is the on-demand revalidation step mandatory for the preview work? currently, a few platforms such as Netlify don't support that feature yet