• Integrations

Use Next.js with Prismic

Learn how to build websites with Next.js and Prismic.

Overview

Prismic has a first-party Next.js integration that supports all of Prismic’s features:

Your favorite Next.js features are also supported:

This page teaches you how to set up a Next.js website with Prismic.

Set up a Next.js website

Prismic can be added to new or existing Next.js websites. Follow these steps to set up a Next.js project.

  • Create a Prismic repository

    From the Prismic dashboard, create a Prismic repository. Select Next.js.

    A screenshot of the Prismic dashboard.

    The Prismic dashboard where you can create a new repository.

    When asked to select a starter, select Connect your own web app.

  • Set up a Next.js project

    Follow the setup instructions shown in your Prismic repository.

    A screenshot of project setup steps in a Prismic repository.

    Project setup steps in a Prismic repository.

    The instructions guide you through creating a new Next.js project (if needed) and adding Prismic using @slicemachine/init.

    The @slicemachine/init command performs the following:

  • Model page content

    Content modeling is the process of converting page designs into structured fields. We recommend adding support for a homepage and general pages.

    See the Recommended models guide for instructions.

  • Set up content previews

    Content writers can preview content on your website before publishing.

    See the Live previews and Preview draft content sections for instructions.

  • Deploy your website

    Before content writers can collaborate on the website, you’ll need to host it online.

    See the Deploy section for instructions.

  • Publish content

    Your Next.js website is now set up and ready for content. Visit your Prismic repository to build pages.

    To recap, you completed the following:

    • Created a Prismic repository to store your website’s content.

    • Set up a Next.js project and integrated Prismic.

    • Prepared your website for a homepage and general pages.

    • Added support for live and full-website previews.

    • Deployed your website to your hosting provider.

    Continue adding slices and other content models as you develop your website.

Create pages

Website pages are managed in Prismic using page types. Page types are created in Slice Machine.

Learn how to model pages and create Next.js page files in the Content Modeling guide. In the guide, you’ll find code snippets to bootstrap your pages.

Define routes

Prismic needs to know your website’s routes to fill in link URLs. Configure the routes constant in your project’s prismicio.ts with a set of route resolvers.

This example includes routes for a homepage, general pages, and a blog.

prismicio.ts
// `type` is the API ID of a page type.
// `path` determines the URL for a page of that type.
const routes: Route[] = [
  { type: "homepage", path: "/" },
  { type: "page", path: "/:uid" },
  { type: "blog_post", path: "/blog/:uid" },
];

Your route resolvers should match your Next.js file-system-based routes. Here are some commonly used routes:

Route resolver pathNext.js file-system route
/app/page.tsx
/:uidapp/[uid]/page.tsx
/blog/:uidapp/blog/[uid]/page.tsx
/:grandparent/:parent/:uidapp/[...path]/page.tsx

Create slices

Page content is written using reusable page sections called slices. Slices are created in Slice Machine.

Write React components

Slice Machine generates a bootstrapped React component when a slice is created. You can find the generated files in src/slices or whichever slice library was selected.

Once your slice is configured with fields, edit the slice’s index.tsx file to display the slice’s content.

Here is an example of a Call to Action slice. It displays some text and a link using a rich text and link field.

src/slices/CallToAction/index.tsx
import type { Content } from "@prismicio/client";
import { PrismicRichText, type SliceComponentProps } from "@prismicio/react";
import { PrismicNextLink } from "@prismicio/next";

type CallToActionProps = SliceComponentProps<Content.CallToActionSlice>;

export default function CallToAction({ slice }: CallToActionProps) {
  return (
    <section className="flex flex-col gap-4 p-8">
      <PrismicRichText field={slice.primary.text} />
      <PrismicNextLink field={slice.primary.link} className="button" />
    </section>
  );
}

Fetch content

Use @prismicio/client and its methods to fetch page content.

Set up a Prismic client

Create a prismicio.ts file to centralize your Prismic client setup. How you set up a Prismic client depends on which Next.js router your website uses.

This file contains route resolvers, Next.js data cache settings, and default Prismic client settings.

src/prismicio.ts
import {
  createClient as baseCreateClient,
  type ClientConfig,
  type Route,
} from "@prismicio/client";
import { enableAutoPreviews } from "@prismicio/next";
import sm from "../slicemachine.config.json";

export const repositoryName = sm.repositoryName;

// TODO: Update with your route resolvers.
const routes: Route[] = [
  { type: "homepage", path: "/" },
  { type: "page", path: "/:uid" },
  { type: "blog_post", path: "/blog/:uid" },
];

export function createClient(config: ClientConfig = {}) {
  const client = baseCreateClient(repositoryName, {
    routes,
    fetchOptions:
      process.env.NODE_ENV === "production"
        ? { next: { tags: ["prismic"] }, cache: "force-cache" }
        : { next: { revalidate: 5 } },
    ...config,
  });

  enableAutoPreviews({ client });

  return client;
}

The above fetchOptions includes the following Next.js cache settings:

  • In development: Caches Prismic API calls for 5 seconds.
  • In production: Caches Prismic API calls indefinitely until the prismic tag is revalidated.

Fetch content in pages and slices

Import createClient() from prismicio.ts and create a client. Use the client to fetch content.

How you fetch content depends on which Next.js router your website is using.

This example page fetches content for a /[uid] dynamic route.

src/app/[uid]/page.tsx
import type { Metadata } from "next";
import { SliceZone } from "@prismicio/react";
import { createClient } from "@/prismicio";
import { components } from "@/slices";

type Params = { uid: string };

export default async function Page({ params }: { params: Promise<Params> }) {
  const { uid } = await params;
  const client = createClient();
  const page = await client.getByUID("page", uid);

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

You can fetch content in slices the same way. This example fetches a Settings document.

src/slices/ContactForm/index.tsx
import { Content } from "@prismicio/client";
import { SliceComponentProps } from "@prismicio/react";
import { createClient } from "@/prismicio";

type ContactFormProps = SliceComponentProps<Content.ContactFormSlice>;

export default async function ContactForm({ slice }: ContactFormProps) {
  const client = createClient();
  const settings = await client.getSingle("settings");

  // ...
}

Display content

Prismic content can be displayed using @prismicio/react and @prismicio/next.

Here are the most commonly used components in Next.js websites:

Live previews in the Page Builder

Content writers can preview content live while editing in the Page Builder. Each slice in a page is shown as a live-updating thumbnail.

A screenshot of a page with live previews in the Page Builder.

A page with live previews in the Page Builder.

Set up live previewing

Live previews require a special /slice-simulator route in your Next.js website.

  • Create a page at /slice-simulator

    How you set up the /slice-simulator page depends on which Next.js router your website uses.

    Create a file at app/slice-simulator/page.tsx with the following contents.

    app/slice-simulator/page.tsx
    import {
      SliceSimulator,
      SliceSimulatorParams,
      getSlices,
    } from "@slicemachine/adapter-next/simulator";
    import { SliceZone } from "@prismicio/react";
    import { components } from "@/slices";
    
    export default async function SliceSimulatorPage({
      searchParams,
    }: SliceSimulatorParams) {
      const { state } = await searchParams;
      const slices = getSlices(state);
    
      return (
        <SliceSimulator>
          <SliceZone slices={slices} components={components} />
        </SliceSimulator>
      );
    }
  • Set the simulator URL in the Page Builder

    Navigate to your Prismic repository and open a document.

    Click the ”” button next to the Publish/Unpublish button in the top-right corner. Select Live preview settings.

    A screenshot of the live preview settings menu option in the Page Builder.

    The live preview settings menu option.

    In the modal, enter http://localhost:3000/slice-simulator and click Save.

Preview draft content

Content writers can preview content on your website before publishing.

@slicemachine/init performs most of the setup for you during project setup. However, there are a few steps to complete manually.

Set up previews in Next.js

@prismicio/next provides helpers and a component to support content previews. How you set up content previews depends on which Next.js router your website uses.

  • Add <PrismicPreview> to app/layout.tsx

    <PrismicPreview> adds the Prismic toolbar and event listeners. The website automatically refreshes when a content draft is saved.

    app/layout.tsx
    import { type ReactNode } from "react";
    import { PrismicPreview } from "@prismicio/next";
    import { repositoryName } from "@/prismicio";
    
    export default function RootLayout({ children }: { children: ReactNode }) {
      return (
        <html lang="en">
          <body>{children}</body>
          <PrismicPreview repositoryName={repositoryName} />
        </html>
      );
    }
  • Call enableAutoPreviews() with your Prismic client

    enableAutoPreviews() configures a Prismic client to automatically fetch draft content during a preview. Include it in your prismicio.ts file.

    prismicio.ts
    import {
      createClient as baseCreateClient,
      ClientConfig,
    } from "@prismicio/client";
    import { enableAutoPreviews } from "@prismicio/next";
    import sm from "../slicemachine.config.json";
    
    export const repositoryName = sm.repositoryName;
    
    export function createClient(config: ClientConfig = {}) {
      const client = baseCreateClient(repositoryName, config);
    
      enableAutoPreviews({ client });
    
      return client;
    }
  • Create an /api/preview endpoint

    This endpoint enables Draft Mode and redirects a content writer to the previewed document. It uses redirectToPreviewURL().

    app/api/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();
    
      return await redirectToPreviewURL({ client, request });
    }
  • Create an /api/exit-preview endpoint

    This endpoint ends a preview session. It is called by the Prismic toolbar when closing a preview. It uses exitPreview().

    app/api/exit-preview/route.ts
    import { exitPreview } from "@prismicio/next";
    
    export function GET() {
      return exitPreview();
    }

Set up previews in Prismic

After setting up previews in your Next.js project, set up previews in Prismic.

  • Open your preview settings

    Navigate to your Prismic repository and go to Settings > Previews.

    A screenshot of the previews settings page.

    The previews settings page.

  • Create a preview

    In the Manage your previews section, create a preview using the following values:

    FieldValue
    Site nameDevelopment
    Domain for your applicationhttp://localhost:3000
    Preview route/api/preview

    Click Create my preview.

Deploy

To deploy your website, follow the instructions for deploying Next.js with your chosen hosting provider:

Handle content changes

Your app needs to be notified or rebuilt when your content changes in Prismic. How you set up your website to handle content changes depends on which Next.js router your website uses.

  • Create a webhook

    Add a Prismic webhook to clear the Next.js fetch() cache when your content changes in Prismic.

    Follow the Create a webhook instructions in our webhooks documentation using these values:

    FieldValue
    Name”Display published content”
    URLYour app’s deployed URL + /api/revalidate (e.g https://example.com/api/revalidate).
    TriggersOnly check “A document is published” and “A document is unpublished”.

    You do not need to set up a webhook with your hosting provider.

  • Create a /api/revalidate Route Handler

    Add the following /api/revalidate Route Handler to your Next.js app:

    app/api/revalidate/route.ts
    import { NextResponse } from "next/server";
    import { revalidateTag } from "next/cache";
    
    export async function POST() {
      revalidateTag("prismic");
    
      return NextResponse.json({ revalidated: true, now: Date.now() });
    }

SEO

Prismic websites can be optimized for search engines using meta_title and meta_descriptions fields. These fields provide metadata and may improve your website’s ranking.

Internationalization

Prismic supports websites with multiple languages. How you set up internationalization depends on which Next.js router your website uses.

To learn more about Prismic’s locale management, see Locales.

Configure Slice Machine

Slice Machine can be configured in slicemachine.config.json. Add options to the adapter.options property.

slicemachine.config.json
{
  "repositoryName": "example-prismic-repo",
  "libraries": ["./src/slices"],
  "localSliceSimulatorURL": "http://localhost:3000/slice-simulator",
  "adapter": {
    "resolve": "@slicemachine/adapter-next",
    "options": {
      "typescript": true
    }
  }
}
PropertyDescriptionDefault
formatoptional
boolean

Determines if generated files are formatted using Prettier.

true
lazyLoadSlicesoptional
boolean

Determines if slice components are lazy loaded with next/dynamic.

true
typescriptoptional
boolean

Determines if generated files are written in TypeScript or JavaScript. Defaults to true if a project has a tsconfig.json file.

jsxExtensionoptional
boolean

Determines if generated JavaScript files should use a .jsx file extension. Has no effect when TypeScript is used.

false
generatedTypesFilePathoptional
string

The filepath at which generated TypeScript types will be saved.

prismicio-types.d.ts
environmentVariableFilePathoptional
string

The filepath at which the active Prismic environment is stored as an environment variable.

.env.local