Fetch Data

In this article, you’ll learn how to perform queries to the Prismic API to retrieve content in your Next.js application.

Before you proceed

First, you’ll need a project with Next.js and Prismic. If you don’t have one yet, start with the setup step.

Caching errors in Next.js

Multiple users have reported similar errors with data fetching in Next.js versions 13 and 14. We believe that these errors are related to inconsistent caching behavior. For the lastest updates and tips on how to troubleshoot these issues, see our forum thread.

Recommended data fetching method

Next.js has many different ways to fetch data. Prismic works with all data-fetching methods, but Next.js recommends static rendering for the best website performance.

How to fetch data when statically rendering depends on whether or not you are using the App Router or the Pages Router. Next.js introduced the App Router in version 13. In doing so, they changed the way that we fetch data in static websites:

All code snippets below provide examples for both the App Router and the Pages Directory.

We recommend using the App Router for all new projects.

Perform a query

Queries are performed using a client created by the createClient() function exported from prismicio.js.

Here’s a complete example, querying a document of type page by its UID:

  • App Router
  • Pages Directory
App Router
app/[uid]/page.jsx
Copy
import { createClient } from "@/prismicio";

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

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

  return <h1>{page.uid}</h1>;
}
Pages Directory
pages/[uid].jsx
Copy
import { createClient } from "@/prismicio";

export default function Page({ page }) {
  return <h1>{page.uid}</h1>;
}

export async function getStaticProps({ params, previewData }) {
  const client = createClient({ previewData });

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

  return {
    props: { page },
  };
}

In the Pages Directory, createClient() receives the previewData object from getStaticProps(). This enables Prismic’s preview support. See Preview Drafts to learn more about setting up previews.

Caching with the App Router

Data fetching can be cached in the App Router using the cache and next parameters on the fetch() function. You can configure the Prismic client’s cache and next parameters using the fetchOptions parameter.

We recommend the following fetchOptions value for the best performance:

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

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

    prismicNext.enableAutoPreviews({ client })

    return client
  }

When your app is deployed, Prismic requests will be cached and tagged with "prismic". The tag allows for clearing Prismic queries from the fetch() caching using On-demand Revalidation. See the Deploy section for more details on setting up On-demand Revalidation.

While developing your app locally, Prismic requests will be cached for 5 seconds.

The cache and next parameters can be overridden on individual queries as needed.

Copy
const latestBlogPosts = await client.getAllByType('blog_post', {
  fetchOptions: {
    cache: 'no-store',
    next: { tags: ['prismic', 'blog_posts'] },
  },
  limit: 3,
  orderings: [
    {
      field: 'my.blog_post.published_on',
      direction: 'desc',
    },
  ],
})

Query helpers

Here are the most commonly-used query helper methods:

getByUID()

Copy
getByUID(type, uid)
getByUID(type, uid, params)

Queries a document from the Prismic repository with a UID and custom type. type refers to the API ID of the custom type.

Copy
const document = await client.getByUID('post', 'my-first-post')

getSingle()

Copy
getSingle(type)
getSingle(type, params)

Queries a singleton document from the Prismic repository for a specific custom type. type refers to the API ID of the custom type.

For example, here we are querying for the only document of the custom type homepage.

Copy
const document = await client.getSingle('homepage')

getAllByType()

Copy
getAllByType(type)
getAllByType(type, params)

Queries all documents from the Prismic repository for a specific custom type. type refers to the API ID of the custom type. This method may perform multiple network requests. It returns an array containing all matching documents from the repository.

Copy
const documents = await client.getAllByType('article')

Further Learning

There are many more methods for querying the API. All of these queries can accept params options to filter, sort, paginate and translate your query response. See them all in the @prismicio/client Technical Reference.

Use cases

Here are a few common use cases.

Fetch linked data

To pull in content from another document, you must fetch that content in your API query using the graphQuery or fetchLinks option.

With fetchLinks, reference the linked custom type followed by the API ID of the specific field you want to retrieve. For example, if you have a custom type called blog that has a content relationship field that links to a custom type called author, and you want to retrieve the author_name field, your query would look like this:

  • App Router
  • Pages Directory
App Router
app/blog/[uid]/page.js
Copy
import { createClient } from "@/prismicio";

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

  const blogPost = await client.getByUID("blog", "my-blog-post", {
    fetchLinks: "author.author_name",
  });

  return (
    <main>
      <h1>{blogPost.data.title}</h1>
      <em>{blogPost.data.author_link.data.author_name}</em>
    </main>
  );
}
Pages Directory
pages/blog/[uid].js
Copy
import { createClient } from "@/prismicio";

export default function Page({ blogPost }) {
  return (
    <main>
      <h1>{blogPost.data.title}</h1>
      <em>{blogPost.data.author_link.data.author_name}</em>
    </main>
  );
}

export async function getStaticProps({ previewData }) {
  const client = createClient({ previewData });

  const blogPost = await client.getByUID("blog", "my-blog-post", {
    fetchLinks: "author.author_name",
  });

  return {
    props: { blogPost },
  };
}

Once you have adjusted your API query, the linked content will appear in a data object nested in the content relationship field:

Copy
"example_content_relationship": {
  "type": "author",
  "slug": "another-page-title",
  "uid": "jane-johnson",
  "data": {
    "author_name": "Jane Johnson"
  },
  "link_type": "Document",
  "isBroken": false
}

Query a nav menu or config document

In Prismic, you can create a singleton custom type to store site components, like a header, footer, nav menu, or SEO configuration.

To query a singleton, use the getSingle() method with the API ID of the singleton custom type.

  • App Router
  • Pages Directory
App Router
Copy
import { createClient } from "@/prismicio";
import { PrismicLink } from "@prismicio/next";

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

  const menu = await client.getSingle("menu");

  return (
    <ul>
      {menu.data.links.map((link) => (
        <li>
          <PrismicLink field={link.link}>{link.label}</PrismicLink>
        </li>
      ))}
    </ul>
  );
}
Pages Directory
Copy
import { createClient } from "../prismicio";
import { PrismicLink } from "@prismicio/react";

export default function Page({ menu }) {
  return (
    <ul>
      {menu.data.links.map((link) => (
        <li>
          <PrismicLink field={link.link}>{link.label}</PrismicLink>
        </li>
      ))}
    </ul>
  );
}

export async function getStaticProps({ previewData }) {
  const client = createClient({ previewData });

  const menu = await client.getSingle("menu");

  return {
    props: { menu },
  };
}

Query one instance of a repeatable document

On repeatable documents, we recommend adding a UID field — a unique identifier. Prismic formats each document's UID so it is URL-friendly and unique to its custom type.

To query a specific document of a given custom type, like a blog post, you can use the getByUID() method. To use getByUID(), pass the UID and the API ID of the custom type.

  • App Router
  • Pages Directory
App Router
app/hello-world/page.js
Copy
import { createClient } from "@/prismicio";

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

  const page = await client.getByUID("page", "hello-world");

  return <main>{page.data.title}</main>;
}
Pages Directory
pages/hello-world.js
Copy
import { createClient } from "../prismicio";

export default function Page({ page }) {
  return <main>{page.data.title}</main>;
}

export async function getStaticProps({ previewData }) {
  const client = createClient({ previewData });

  const page = await client.getByUID("page", "hello-world");

  return {
    props: { page },
  };
}

You will likely use getByUID() with a page's URL path to generate a page based on the URL. For instance, at /hello-world, you would want to display the document with the UID hello-world. Rather than hard-coding every page by its UID, in Next.js you can use dynamic URL parameters by putting the parameter's name in square brackets: pages/[uid].js. Then you can access the uid parameter and perform a query with it:

  • App Router
  • Page Directory
App Router
app/[uid]/page.js
Copy
import { createClient } from "@/prismicio";

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

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

  return <main>{page.data.title}</main>;
}
Page Directory
pages/[uid].js
Copy
import { createClient } from "../prismicio";

export default function Page({ page }) {
  return <main>{page.data.title}</main>;
}

export async function getStaticProps({ params, previewData }) {
  const client = createClient({ previewData });

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

  return {
    props: { page },
  };
}

This will return a document dynamically, based on the URL, so you can template a repeatable document.

Query all documents

You can query all documents of a certain type with getAllByType().

  • App Router
  • Pages Directory
App Router
app/page.js
Copy
import { createClient } from "@/prismicio";

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

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

  return (
    <ul>
      {pages.map((page) => (
        <li>{page.data.title}</li>
      ))}
    </ul>
  );
}
Pages Directory
pages/index.js
Copy
import { createClient } from "../prismicio";

export default function Page({ pages }) {
  return (
    <ul>
      {pages.map((page) => (
        <li>{page.data.title}</li>
      ))}
    </ul>
  );
}

export async function getStaticProps({ previewData }) {
  const client = createClient({ previewData });

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

  return {
    props: { pages },
  };
}

Query by language

Prismic allows you to publish your content in different languages. By default, the API will return content in your master language. To get content in a different language, add an options object with a lang option and a locale code. Here's an example of how to query the document of the type homepage in French (fr-fr).

  • App Router
  • Pages Directory
App Router
app/page.js
Copy
import { createClient } from "@/prismicio";

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

  const homepage = await client.getSingle("homepage", { lang: "fr-fr" });

  return <main>{homepage.data.title}</main>;
}
Pages Directory
pages/index.js
Copy
import { createClient } from "../prismicio";

export default function Page({ page }) {
  return <main>{page.data.title}</main>;
}

export async function getStaticProps({ previewData }) {
  const client = createClient({ previewData });

  const homepage = await client.getSingle("homepage", { lang: "fr-fr" });

  return {
    props: { homepage },
  };
}

You can render localized content dynamically by including the language in the URL path (e.g. /fr-fr/bonjour-le-monde), like so:

  • App Router
  • Pages Directory
App Router
app/[lang]/[uid]/page.tsx
Copy
import { createClient } from "@/prismicio";

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

  const page = await client.getByUID("page", params.uid, {
    lang: params.lang,
  });

  return <main>{page.data.title}</main>;
}
Pages Directory
pages/[lang]/[uid].js
Copy
import { createClient } from "../prismicio";

export default function Page({ page }) {
  return <main>{page.data.title}</main>;
}

export async function getStaticProps({ params, previewData }) {
  const client = createClient({ previewData });
  const { uid, lang } = params;

  const page = await client.getByUID("page", uid, { lang });

  return {
    props: { page },
  };
}

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.