How to Integrate Contentful and Next.js App Router

This guide will show you how to create a Next.js application using App Router to fetch knowledge base articles from Contentful via React Server Components.
Published
December 13, 2023
Category

Guides

Next.js 13 introduced App Router as a new paradigm for building Next.js applications which supports React Server Components..

While developers can still use the Pages Router for data fetching at the page level, App Router offers a vastly improved approach, enabling server and client-side data fetching within layouts, pages, and individual components. This improvement not only provides more flexibility to craft responsive and rich user experiences but also enhances performance. It achieves this by minimizing round-trips between the user’s browser and server, and by implementing smarter caching and fetch memoization strategies.

This guide will show you how to create a Next.js application using App Router to fetch knowledge base articles via React Server Components. We’ll walk through setting up a listing and detail page that renders content and revalidates page data when it’s changed and published in Contentful. Lastly, we’ll deploy this application to Vercel, where content can be previewed from both Contentful and Vercel. All the sample code is stored on GitHub for reference.

Setting Up: Next.js and Contentful

Prerequisites

Before getting started, ensure you have the following:

  • A Contentful account. If you don't have one, you can sign up here.

  • A Vercel account. If you're new to Vercel, sign up here.

  • Intermediate knowledge of JavaScript and React.js.

  • A system that supports Node.js. You must have `npm` installed.

Creating a content model in Contentful

  1. Accessing the dashboard: Open your browser and head over to Contentful.

  2. Creating a space: Start by creating a new space. This will contain all your content models and content.

    For this tutorial, we'll be setting up a knowledge base. Create a content model named knowledgeArticle. This will define the structure of your articles.

  3. Defining the content model: For this tutorial, we'll be setting up a knowledge base. Create a content model named knowledgeArticle. This will define the structure of your articles. 

    Add the following fields to the content model.

  4. Add the following fields to the content model:

    • title (Short text): The title of the article.

    • slug (Short text): A URL-friendly version of the title.

    • summary (Short text): A brief overview of the article.

    • details (Rich text): The main content of the article.

    • date (Date & time): The publication date of the article.

    • articleImage (Media): An image representing the article.

    • authorName (Short text): The name of the article's author.

    • categoryName (Short text): The category to which the article belongs.

  5. Populating with sample data: With these fields in place, article content can now be entered with the knowledgeArticle content type. Add a few sample knowledge articles.

    Add a few sample knowledge articles.

Setting up Contentful's Content Delivery API

We will use Contentful’s Content Delivery API for fetching content inside our app. This API is read-only and lets applications retrieve content stored in a Contentful space.

Navigate to the API section in your Contentful dashboard and create a new API key. This key will be placed in an environment variable for the Next.js application to authenticate and retrieve content articles. For a detailed walkthrough, check out Contentful's official documentation.

Creating the Next.js application

With your content model ready in Contentful, it's time to set up the Next.js application:

  1. Creating the app: In your terminal or command prompt, navigate to your desired directory and run the following command to create a new Next.js application:

    npx create-next-app@latest –js

    Follow the on-screen prompts, and a new project will be set up.

  2. Testing your setup: To ensure everything was set up correctly, navigate to your project directory and start the development server:

    npm run dev

  3. Open your browser and head to http://localhost:3000. You should see the default Next.js starter page.

In the next sections, we'll integrate Contentful with our Next.js app.

Routing in App Router: Making a listing and detail page

Setting up environment variables

Before diving into the routing, ensure you have the necessary environment variables set up. These variables will be used to securely access your Contentful data. Locally, create a .env.local file and set these variables to your Contentful Space ID, access token, and preview access token. 

The Contentful Space ID can be retrieved from Settings > General Settings in Contentful. In order to retrieve the access token and preview access token you must create a new API key. This can be done by navigating to the Settings > API keys settings then clicking the Add API key button. Later in this guide, we will use the Contentful access token for retrieving published content and the preview access token for retrieving draft content that is not yet ready for the public.

Fetching content from Contentful

In this guide, we will fetch content via Contentful’s GraphQL API. This logic will be encapsulated within /lib/api.js. For demonstration purposes, we have hardcoded some of the fetch logic such as specifying a default fetch limit to the top three articles. Feel free to customize this file to meet your needs and requirements.

Create a new lib directory in the root of your project then create a new JavaScript (.js) file within the lib directory named api.js. Paste the following code into that file and save.

Note that this file contains preview and isDraftMode references which is necessary for supporting Contentful content preview. We will walk through this functionality in a later section.

Listing the knowledge base on the homepage

With our code ready to fetch content from Contentful, we are ready to retrieve the knowledge article content on our homepage. We’ll start by updating the homepage page.js file to fetch articles using the lib/api.js code. Then, we’ll modify the JSX (JavaScript XML) that will render the HTML containing the article field content from Contentful. At the end, we’ll review how Next.js App Router optimizes this page for speed and responsiveness.

  1. Open the app/page.js file for the homepage and add the following placeholder component JavaScript code. Note that since we will be calling functions with asynchronous data fetching, the function declaration for the Home component includes the async keyword:

  2. Import and add a new line and that calls getAllArticles from lib/api.js then store the articles result in a variable:

  3. Before updating the JSX to render article fields from Contentful, update next.config.js to allow the Contentful image hostname. This will allow us to use the next/image component with images from Contentful.

  4. Lastly, let’s update the JSX to include a heading, description, and list of articles markup. We’ll use the JavaScript array method, map, to iterate over the articles and TailwindCSS for styling.

    Note that JavaScript expressions, like {article.authorName}, are used to dynamically render Contentful’s field content for each article.

    Below is the complete page.js file after these updates.

Once these code updates have been saved, navigate your browser to http://localhost:3000 and see your new article listing:

Once these code updates have been saved, navigate your browser to http://localhost:3000 and see your new article listing

Add an article detail page

  1. Now let’s add a detail page for users to view full knowledge article content. 

    Install the Contentful Rich Text React renderer package so we can render Rich Text content that is stored in Contentful for article detail content.

    npm install --save @contentful/rich-text-react-renderer


  2. Create a new page.js file in the project at app/articles/[slug]/page.js and paste in the following placeholder code for the detail page. 

    The “[slug]” directory name annotates a dynamic segment in Next.js which enables Dynamic Routes for article detail pages. For this guide, “[slug]” will be populated with data from Contentful (the slug text field) so Next.js can construct dynamic URLs at build time or request time.

  3. Next, retrieve the slug dynamic segment from the params prop and pass that into the getArticle function to fetch the matching article for this detail page.

  4. At the moment, this page will be rendered when a user navigates to this URL. However, we can improve performance by retrieving all articles and rendering the detail pages at build time using static rendering. Let’s add the Next.js function, generateStaticParams, that will return an array of objects containing the dynamic segment, slug, to statically render at build time.

  5. Finally, let’s update the JSX so it renders all article detail content. The complete styled page.js file is specified below.

Save and navigate to one of the knowledge article detail pages from the homepage to see the new updates.

How App Router optimizes for frontend performance

Next.js App Router, by default, leverages React Server Components (RSC) to render and cache HTML on the server. This significantly enhances page speed and user experience in several ways:

  1. Data fetching: Server-side rendering enables fetching data from a server located closer to the data source, reducing the time it takes to retrieve data.

  2. Caching: Since data fetching is performed on a server, it's possible to cache results across multiple users, reducing the need for repeated fetching and rendering.

  3. Bundle size: Rendering components on the server means less JavaScript is sent to a user's browser. This is beneficial for users on slow connections and less powerful devices since they no longer need to parse and execute as much JavaScript.

In this example, the fetching of articles from Contentful is optimized to retrieve and cache content across multiple users. Next.js enhances this process further by using static rendering for pages where request time information isn’t needed. This means the content is rendered at build time and then cached on a CDN, significantly boosting page speed and efficiency.

On-demand revalidation: Updating content in Next.js from Contentful

We now have a knowledge base article listing and detail page that have both been optimized to leverage React Server Components and static rendering to ensure that they load quickly for users. But what happens when a content editor changes content? There is currently no communication from Contentful to the Next.js application when content is updated. For that, we will add on-demand revalidation. This can be accomplished in three steps:

  1. Use tags when fetching content: Next.js allows us to attach tags to any or all of our fetches for content which will associate specific types of content with pages and our UI.

  2. Create a revalidation API in Next.js: This will be an API called from Contentful that will inform Next.js that it needs to purge the cache for any newly updated content.

  3. Configure Contentful to on-demand revalidate: Using Contentful webhooks, we will call the Next.js revalidation API and update the page from Contentful every time an article is published.

Use tags when fetching content

Earlier when we added the code for fetching content from Contentful in /lib/api.js, you may have noticed that we provided a next property in our fetch request.

This line specifies in Next.js that any time there is a component that uses this fetch function, its cache can be purged on-demand via revalidateTag (more on this in the next step). Since both our article listing and detail pages are using this, we only need to add an API for the revalidation.

It’s important to note that this guide is using a single articles tag for caching and revalidating the cache for the listing and detail pages. This works well for this example that has only a few pages, but for an application that has hundreds of detail pages, it is better to include a page-specific tag so we can revalidate the cache for an individual page without purging the cache for all pages.

Create a revalidate API in Next.js

We need a mechanism of allowing Contentful to communicate with Next.js whenever an article updates. For this we will create an API in Next.js with a route handler.

Open the .env.local file from earlier, add a new environment variable, and set it to a secret value that only Contentful will know. We will use this value to verify that only Contentful is making requests to our new revalidate API.

CONTENTFUL_REVALIDATE_SECRET=ContentfulOnlySecret123

Create a new file in your project at app/api/revalidation/route.js. Similar to page.js, route.js is a reserved file name that specifies you are creating a custom request handler. Paste in the following code for the route handler’s implementation.

This route handler does two key things:

  1. It checks for the existence of a x-vercel-reval-key header value which will restrict calls to this API to Contentful via the CONTENTFUL_REVALIDATE_SECRET we set earlier.

  2. It executes revalidateTag(“articles”) which will purge the cache for our components that are fetching Contentful article content.

Configure Contentful to on-demand revalidate

Now that the Next.js application is configured to have the listing and detail pages revalidated from Contentful, let’s configure the necessary webhook for revalidating on content publish.

Log into your Contentful space and go to Settings > Webhooks and click the Add Webhook button. From here you can set the following settings to call the revalidate API for on-demand revalidation. Click Save when you are finished.

Note that Contentful will need a URL that is publicly accessible for the revalidation to succeed. We will come back to this screen after we have deployed the website to set PLACEHOLDER_URL to the final domain.

Now that the Next.js application is configured to have the listing and detail pages revalidated from Contentful, let’s configure the necessary webhook for revalidating on content publish.

Using Content Preview with Contentful & Next.js

The last piece we will configure before we deploy this website is configuring Contentful Content Preview. Content Preview adds crucial functionality for content editors to preview their content before it is published to the public. Both Contentful and Next.js has functionality to support this with three steps:

  1. Add Draft Mode APIs to Next.js for toggling preview content: Draft Mode is a feature of Next.js that allows a page to switch between dynamic or static rendering based on the presence of a Draft Mode cookie. This allows preview content to be fetched at runtime instead of published content. We will use route handlers for toggling this cookie value.

  2. Call draftMode() on the listing and detail page: We will add this function on our existing pages to determine which content the user should see at request time which we’ll pass to our fetch call.

  3. Connect Contentful to Next.js via Content Preview settings: Since we need Contentful to communicate with the Next.js application when a content editor should see preview content, we will update the Content Preview settings to enable Draft Mode.

Content Preview is critical for content editors to preview content before they publish. However, it’s very important that this functionality be implemented correctly by following the steps below and tested to ensure that the website does not inadvertently expose draft content on the public website.

Add Next.js Draft Mode APIs

We will again use Next.js route handlers for handling requests from Contentful. We should be sure that requests to enable Draft Mode are only coming from Contentful. Open .env.local and add a new secret environment variable that we will verify in the Draft Mode route handler.

CONTENTFUL_PREVIEW_SECRET=ContentfulPreviewSecret123

Next, add a Next.js route handler at /app/api/draft/route.js. This API will be responsible for enabling draft mode:

Similar to the revalidation API, there are two key actions being performed in this route handler.

  1. It verifies that the slug and secret are valid and that the secret matches the environment variable we just configured.

  2. It executes draftMode().enable() to set the user’s preview cookie before redirecting them to the page.

We have provided the API for enabling Draft Mode in Next.js now let’s add one for disabling it. Add another route handler at /app/api/disable-draft/route.js:

This route handler calls draftMode().disable() which toggles off Draft Mode for the current user and they will now see published content.

Use draftMode() on the listing and detail pages

With our route handler updates complete, let’s update the listing and detail pages to check whether they should use preview or published content when rendering.

Edit the homepage at /app/page.js and update the first two lines of the component:

The first line now calls draftMode() to determine whether it has been enabled and stores that into the isEnabled variable. This variable is then passed to getAllArticles which is already written to return preview content if this value is set to true. We are also hardcoding a limit of 3 articles but this can be updated to any value that fits your requirements. The homepage is now ready to display preview content.

Edit the detail page at /app/articles/[slug]/page.js and update the first two lines of the component to perform the same logic as the listing.

Configure Contentful live preview settings

Our Next.js changes are finished and we are ready to configure Contentful to point to Next.js and preview content. 

  1. Open Contentful and navigate to Settings > Content Preview and click the Create preview platform button. 

  2. Provide Name and Description and then select Knowledge Article from the Select content types dropdown.

  3. Under Knowledge Article, point Contentful to our draft API endpoint containing the secret and slug to enable Draft Mode. For now, this can use localhost:3000.

Our Next.js changes are finished and we are ready to configure Contentful to point to Next.js and preview content.

To test these changes, update one of your knowledge base articles, do not publish, and click the Open Live Preview link in the Contentful sidebar.

To test these changes, update one of your knowledge base articles, do not publish, and click the Open Live Preview link in the Contentful sidebar.

Now that Live Preview is configured, we are ready to deploy our application to Vercel and see Next.js App Router with on-demand revalidation and Draft Mode working on a live website!

Deploying to Vercel

Our Next.js application is pulling in knowledge base article content and we have configured Contentful to communicate with our application when it needs to revalidate its cache so users see new content. The last step is to deploy our application to Vercel where it will be available globally for users to view.

Vercel is a frontend cloud that will handle building, deploying, and scaling our applications automatically to meet user demand. Deploy your Next.js + Contentful website by following these steps:

Publish your code to git

If you have not done so already, create a new git repository on GitHub, Bitbucket, or GitLab then push your code to the repository. We will use GitHub. 

Be sure to update the snippet below with your GitHub username and repository name.

Import the git repository

Sign up or login to your Vercel account and import your project using the import flow and click Import.

Sign up or login to your Vercel account and import your project using the import flow and click Import.

Vercel will detect that you are using Next.js and will enable the correct build and output settings for you.

Add environment variables

Our integration requires a few environment variables to be set. Expand the Environment Variables accordion and set CONTENTFUL_SPACE_ID, CONTENTFUL_ACCESS_TOKEN, CONTENTFUL_PREVIEW_ACCESS_TOKEN, CONTENTFUL_PREVIEW_SECRET, and CONTENTFUL_REVALIDATE_SECRET ensuring that they match the appropriate values also configured in your Contentful settings.

Our integration requires a few environment variables to be set.

Deploy

Click the Deploy button and Vercel will build and deploy your new website!

Click the Deploy button and Vercel will build and deploy your new website!

Update Contentful settings

Before we update content and browse the new website, we should make some updates in Contentful to be sure that it is using the correct URL for on-demand revalidation and content previews.

To update the revalidate webhook to use the new website, navigate to Contentful and go to Settings > Webhooks and select the Revalidate webhook. Click Webhook settings and update the domain in the URL so it matches the newly deployed website domain. The full URL should be similar to:

https://contentful-nextjs-app-router.vercel.app/api/revalidation

Click Save.

Next, update the content preview URL by going to Settings > Content preview. Select Knowledge Article Preview and update the domain under Knowledge Article from http://localhost:3000 to your new website domain. The full URL should be similar to:

https://contentful-nextjs-app-router.vercel.app/api/draft?secret=<your content preview secret>&slug={entry.fields.slug}

Click Save. You are now ready to browse your knowledge base article website and let content editors draft new and updated content!

Review

To recap what we’ve learned in this blog post: We created a new Contentful space for managing knowledge base article content.

Then, we created a new Next.js application and using App Router, created listing and detail pages that pulled knowledge base article content from Contentful.

Using the latest caching and rendering methods available in Next.js, we ensured that users will see this content as quickly as possible.

To allow content editors to see their published content immediately and also be able to preview content, we added on-demand revalidation and draft mode in Next.js.

We then configured Contentful to communicate with our website whenever content changes or needs to be previewed.

Last but not least, we deployed the new website to Vercel where users can view our articles across the globe while still ensuring that our team can update this content quickly and easily in Contentful. All the sample code is stored on GitHub for reference.

Start building

Use your favorite tech stack, language, and framework of your choice.

About the author

Don't miss the latest

Get updates in your inbox
Discover new insights from the Contentful developer community each month.
add-circle arrow-right remove style-two-pin-marker subtract-circle remove