---
title: "Next.js for Acquia: Content Types"
date: "2022-04-27T18:30:29+00:00"
summary:
image:
type: "article"
url: "/acquia-cloud-platform/help/90321-nextjs-acquia-content-types"
id: "6fbf1860-4c1d-4acc-a7c3-30c528d3174b"
---

Table of contents will be added

![Terminal output showing page build times and sizes for a web application, with various URLs and load times in milliseconds.](https://acquia.widen.net/content/530a6f46-7393-4bbb-815e-4f2cf59c799f/web/url_35900f1a1a6bfe71600a41baa3567ecb.webp)

Goal
----

Create a custom content type in Acquia CMS and render the content in Next.js using the next-acms.

Prerequisites
-------------

*   You have a [working build of Acquia CMS](/tutorial/nextjs-acquia-setting-acquia-cms) for headless development setup.
    
*   You next.js project is connected to your Acquia CMS headless install (see [tutorial](/tutorial/nextjs-acquia-nextjs-startkit-acquia-cms))
    

Overview
--------

Here are the step we’ll cover in this tutorial:

1.  Define a Book content type with fields in Acquia CMS and expose the content to Next.js.
2.  Build a /books page to display all published books in Next.js and link it in the.
3.  Build a book page in Next.js to view the content using React components.

Note

This tutorial was written in collaboration with Chapter Three.

1.  Create the Book Content Type
    ----------------------------
    
    For our example, we are going to use a **Book** content type with the following fields:
    
    1.  Title (title) - Title field
    2.  Body (body) - Text (formatted, long)
    3.  Author (field\_display\_author) - Reuse existing field from Article content type.
    4.  Image (field\_book\_image) - Media (Image)
    
    ![Admin interface for managing book fields, showing labels, machine names, and field types like "Body" and "Display Author" with entity references.](https://acquia.widen.net/content/a50ee5dc-e5ba-4469-ad4e-8be262b8a6af/web/url_8bbf4caef51aecf132c6187878b1d2f4.webp)
    
2.  Create Pathauto pattern
    -----------------------
    
    Next.js uses the [decoupled router](https://www.drupal.org/project/decoupled_router) module in Drupal to find content (resource) based on its URL alias. For this to work, the node always needs a URL alias. We can ensure this by setting a Pathauto pattern.
    
    Create a Pathauto pattern for Book with the following pattern: books/Next.js on Acquia: Customizing content types
    
    Once the content types have been created, you may go ahead and fill in some sample content.
    
    ![Admin interface showing URL alias patterns for articles, books, events, pages, persons, and places. "Book pattern" is highlighted.](https://acquia.widen.net/content/669d7dd8-d3b5-4a8c-a2d5-a10e30fd36c6/web/url_777b33e5361bccb778dbf4fbd3ef8f73.webp)
    
3.  Set Book as a Next.js Entity Type
    ---------------------------------
    
    In Acquia CMS, go to Administration > Configuration > Web services > Next.js sites > Entity Types and add the Book content type with a “Site selector” site resolver.
    
    ![Web interface for editing "node.book" settings, including entity type and site resolver configuration. Options to save or delete changes are visible.](https://acquia.widen.net/content/65519eaf-3d51-4ade-a1ef-1da86cbbefdb/web/url_8dec472181f4d9cf0459a21ab366e7fa.webp)
    
    Note
    
    Revalidation Next.js has an experimental feature to revalidate content with Next.js when content in Drupal is updated (similar to Drupal cache tags). You may enable this and node pages in Next.js should update when content is updated in Drupal. The default cache lifetime is 15 minutes and Next.js will revalidate after this time.
    
4.  Add books to the Drupal menu
    ----------------------------
    
    As Next.js pulls Drupal's menu through, if we want to see our books page in the Next.js navigation, we must add it to the Menu.
    
    Create a new menu item in the Main Navigation menu with a title of "Books" and a URL of `/books`
    
    **Note**: `/books` will not exist in Drupal but Next.js will be able to find a route for it within the Next.js application.
    
    ![Website admin panel showing menu navigation options like Home, Articles, Events, People, Places, and Books, with edit and delete buttons.](https://acquia.widen.net/content/5b60027a-04f7-45d4-8034-bd16595781ba/web/url_7d3dc257d8912b5c0e90025ec97266cc.webp)
    
5.  A page with all books
    ---------------------
    
    Now that our content types are created and we have some default content, we can pull this content into our Next.js site and display it. To do this, we are going to use the Next.js for Drupal framework that interacts with Drupal’s JSON:API implementation.
    
6.  Fetch a list of books
    ---------------------
    
    Let’s start by creating a new page to show all our books.
    
    1.  Create a new file called `books.tsx` under `pages/books.tsx`
    2.  Next.js requires two function to fetch and display data:
        1.  `getStaticProps` to fetch data
        2.  a React page component to display data
    
    Let’s add a scaffolded React component:
    
         import { Layout } from "components/layout"import { PageHeader } from "components/page-header"export default function BooksPage({ books, menus }) { return (    No content found.   )}
    
    Here, we’re importing the `Layout` and `PageHeader` React components and using them inside our `BooksPage` component to render our page template. Take a look at `pages/articles.tsx` for a similar layout. Here we’re looking to keep the look and feel consistent across the site. The Acquia CMS starter template comes with Tailwind CSS out of the box. We can use utility classes to style our book collection. Lets pull our book content from Acquia CMS by adding a function called `getStaticProps` with the following:
    
         import { getResourceCollectionFromContext } from "next-drupal"import { getMenus } from "lib/get-menus"export async function getStaticProps(context) { const books = await getResourceCollectionFromContext("node--book", context)  return { props: { books, menus: await getMenus(), }, }}
    
    `getResourceCollectionFromContext` is a helper function from next-drupal. Here we are telling next-drupal to fetch a collection of `node-book` resources.
    
    The `props` returned from `getStaticProps` are passed then to our `BooksPage` component.
    
    If you add a `console.log(books)` in your `BooksPage` component you should see it log the sample books you created above.
    
         export default function BooksPage({ books, menus }) { //  console.log(books) // …
    
    If you look at the content of books, you will notice `getResourceCollectionFromContext` returns the `node—books` will all the fields. Since we only care about some of the fields, let’s tell JSON:API to only return a subset of the fields.
    
    Note
    
    💡 Fetching only the data we need is a best practice. Smaller payloads means faster transfer and processing keeping the application lean and fast.
    
          import { DrupalJsonApiParams } from "drupal-jsonapi-params"const books = await getResourceCollectionFromContext("node--book", context, { // For the node--book, only fetch the following fields. params: new DrupalJsonApiParams() .addInclude(["field_book_image.image", "field_display_author"]) .addFields("node--book", [ "title", "body", "path", "field_display_author", "field_book_image", ]) .getQueryObject(),})
    
    Next, let’s take a look at `field_display_author` and `field_book_image`. These are entity reference fields and don’t include the metadata we need on the book entity so we must tell the JSON:API to **include** these entities in the response. We do so with the addInclude function.
    
    Note
    
    💡 We use field\_book\_image.image because we also want to include the data for the actual image i.e. the url of the image on Drupal.
    
7.  Display a list of books
    -----------------------
    
    Once we have our books data, we can go ahead and render a list of books in the React page component. Lets update `BooksPage` to look like this:
    
         export default function BooksPage({ books, menus }) { return (    {books?.length ? (  {books.map((book) => (  ))}  ) : ( No content found. )}   )}
    
    This introduces a new React component that doesn’t exist yet: `NodeBookTeaser`. We need to create this component before this page will render without error.
    
    Create a new file called `components/node--book.tsx` with the following component in it:
    
         import Link from "next/link"import { MediaImage } from "components/media--image"export function NodeBookTeaser({ node }) { return (  {node.field_book_image & (      )}   {node.field_display_author?.title ? (   {node.field_display_author?.title}   ) : null}    {node.title}   {node.body && (  className="text-xs text-gray-600" dangerouslySetInnerHTML={ { __html: node.body.processed } } /> )}   )}Here you can see the React component is doing a number of things:  Its templating with HTML tags like , ,  and . Its passing objects onto other React components to render ( and ) Its using tailwind CSS inline to style HTML components Its working with the book node object to conditionally render components (similar to how would in twig).   Note  MediaImage is a component that comes with the Acquia CMS starter kit for rendering images managed by the Media module.        Now with this component defined, we must import it in our Books page to use it:  import { NodeBookTeaser } from "components/node--book"export default function BooksPage({ books, menus }) {…That’s it. We now have a Books page built with data from Drupal. But if you click on a book link, you’ll find it doesn’t work yet.        A page for every book    The next step is to create a page for every book. This page will display additional information about each book.  The starter comes with a pages/[[...slug]].tsx page. This is a special page. It acts as an entry point for content or nodes that are created on Drupal. Let’s tell this page to build pages for node—book resources. To do so there are a number of places where we have to update the slug:  Import the node--book component (like we did in pages/books.tsx) Add node--book to the CONTENT_TYPES constant Update the NodePage component to use a NodeBook component (which we’ll need to create) for book type nodes. Specify the JSON:API query modifying parameters for the book content type.  So lets start by importing node--book component we previously created. You can place this at the top of the file:  import { NodeBook } from "components/node--book"This will make Next.js break because NodeBook doesn’t actually exist yet. We created NodeBookTeaser but not NodeBook. So lets create a stub in components/node--book.tsx for now that we can revisit later:  export function NodeBook({ node }) { return {node.title}}Next, Update the CONTENT_TYPES variable and add node—book.   const CONTENT_TYPES = [ "node--page", "node--article", "node--event", "node--person", "node--place", "node--book" // ]Then, update getStaticProps to add a condition for the node--book type and load related author and image data.   export async function getStaticProps( context): Promise> { // ... if (type === "node--place") { params.addInclude(["field_place_image.image"]) } if (type === "node--book") { params.addInclude(["field_display_author", "field_book_image.image"]) } const node = await getResourceFromContext(type, context, { params: params.getQueryObject(), }) // ...}Then, update the NodePage component to render the NodeBook component for node—book resources.  Now we have the NodeBook component correctly routed lets revisit it in components/node--book.tsx and revise the output:  That’s it. If you visit the /books page and click on a book title, you should be taken to the book page. To learn more about data fetching and rendering, refer to the Next-Drupal documentation.      Additional Resources   Acquia CMS Starter Kit   Acquia CMS   Next.js for Drupal documentation   Tutorial: Next.js on Acquia: Next.js startkit for Acquia CMS   Tutorial: Next.js on Acquia: Setting up Acquia CMS