Published Jun 19, 202412 min read
Contentful Headless CMS with Next.js: REST API Integration

Contentful Headless CMS with Next.js: REST API Integration

Integrate Contentful, a powerful headless CMS, with Next.js to build modern, high-performance web applications. This guide covers:

  • Setting up a Next.js project and Contentful account

  • Defining custom content models in Contentful

  • Fetching data from Contentful's REST API using axios

  • Rendering content in Next.js components

  • Deploying to Vercel or Netlify with environment variables

Leverage Next.js features like server-side rendering (SSR), static site generation (SSG), and file-based routing. Implement performance optimizations, pagination, content previewing, and real-time updates.

Feature Description
Headless CMS Separate content management from presentation layer
Contentful Cloud-based, scalable, API-first headless CMS
Next.js React framework for server-rendered applications
SSR & SSG Improve performance and SEO with server-side rendering and static site generation
Deployment Deploy to Vercel or Netlify with Git integration and environment variables

Prerequisites

Basic Knowledge Required

To follow this guide, you should have:

  • Basic understanding of JavaScript and React

  • Familiarity with Next.js fundamentals

  • Knowledge of REST APIs and HTTP requests

Setting Up Your Contentful Account

Contentful

If you don't have a Contentful account yet, follow these steps:

  1. Go to https://www.contentful.com/sign-up/ and sign up for a free account.

  2. Log in to your new Contentful account.

  3. Click "Create Space" to create a new space.

  4. Give your space a name and click "Create Space".

Now you have a Contentful account and a space ready to define your content models and start creating content.

Setting Up Next.js Project

Next.js

Create New Next.js Project

To start, open your terminal and run this command to create a new Next.js project:

npx create-next-app@latest my-nextjs-app

Replace my-nextjs-app with your desired project name. This will create a new directory with all the necessary files and dependencies for a Next.js application.

If you already have an existing Next.js project, you can skip this step.

Install Dependencies

Next, navigate to your project directory and install the required dependency:

cd my-nextjs-app
npm install axios

We'll use axios to make HTTP requests to the Contentful API.

Project Structure

After creating the project and installing dependencies, your project structure should look like this:

my-nextjs-app/
├── node_modules/
├── pages/
│   ├── _app.js
│   └── index.js
├── public/
├── styles/
│   └── globals.css
├── .gitignore
├── next.config.js
├── package.json
├── package-lock.json
└── README.md

You'll primarily work with the pages directory, where you'll create new pages or components to fetch and render data from Contentful. You can also create a separate directory, such as components or lib, to store reusable components or utility functions related to the Contentful integration.

With the Next.js project set up and the necessary dependencies installed, you're now ready to configure Contentful and start fetching data from the Contentful API.

Setting Up Contentful

Create a New Space

  1. Log in to your Contentful account at https://www.contentful.com.

  2. Click the "Create Space" button in the top-right corner.

  3. Enter a name for your new space (e.g., "My Next.js Blog").

  4. Select the appropriate region for your space.

  5. Click "Create Space" to finish.

Define Content Models

  1. In your new space, go to the "Content model" section.

  2. Click "Add content type" to create a new content model.

  3. Provide a name for your content type (e.g., "Blog Post").

  4. Click "Add field" to add fields (e.g., "Title," "Body," "Featured Image," etc.).

  5. Configure each field's settings, such as the field type, validation rules, and appearance.

  6. Click "Create" to save your new content type.

Add Sample Content

  1. Go to the "Content" section of your space.

  2. Click "Add entry" and select the content type you created.

  3. Fill in the fields with sample data for testing.

  4. Click "Publish" to make your content live.

  5. Repeat steps 2-4 to add more sample content entries.

Get API Keys and Tokens

  1. In your Contentful space, go to the "Settings" section.

  2. Click "API keys" and then "Content delivery / Preview tokens."

  3. Copy the "Space ID" and "Content Delivery API - access token" values.

  4. (Optional) If you need preview functionality, copy the "Content Preview API - access token" value as well.

You'll use these keys and tokens to connect your Next.js application with the Contentful API.

sbb-itb-1aa3684

Fetching Data from Contentful

Content Delivery API Overview

The Content Delivery API is Contentful's read-only API that allows you to retrieve published content from your Contentful space. It provides a simple way to fetch your content models and entries, which you can then render in your Next.js application. The API uses REST principles and returns data in JSON format.

Making GET Requests

To fetch data from Contentful, you'll make a GET request to the Content Delivery API endpoint. Here's an example using the axios library:

import axios from 'axios';

const contentfulClient = axios.create({
  baseURL: `https://cdn.contentful.com/spaces/${process.env.CONTENTFUL_SPACE_ID}`,
  headers: {
    Authorization: `Bearer ${process.env.CONTENTFUL_ACCESS_TOKEN}`,
  },
});

export async function fetchEntries(contentType, query = {}) {
  const response = await contentfulClient.get(`/entries?content_type=${contentType}`, {
    params: query,
  });
  return response.data;
}

In this example, we create an axios instance with the base URL and authorization header using our Contentful space ID and access token. The fetchEntries function makes a GET request to the /entries endpoint, passing the content type and any additional query parameters.

Handling API Response

The Content Delivery API returns data in JSON format. Here's an example of how to handle the response and extract the required data:

import { fetchEntries } from './contentfulClient';

export async function getBlogs() {
  const response = await fetchEntries('blog');
  const blogs = response.items.map((item) => ({
    id: item.sys.id,
    title: item.fields.title,
    body: item.fields.body,
    // Extract other required fields
  }));
  return blogs;
}

In this example, we call the fetchEntries function with the 'blog' content type. The response contains an items array with the blog entries. We map over this array, extracting the required fields (e.g., id, title, body) from each entry and returning a new array of blog objects.

Best Practices

When fetching data from Contentful, it's important to follow best practices:

  1. Caching: Implement caching to reduce API requests and improve response times.

  2. Pagination: Use pagination to fetch large datasets in smaller chunks, reducing load on the API and improving performance.

  3. Rate Limiting: Be aware of Contentful's rate limiting policies and implement appropriate handling mechanisms.

  4. Error Handling: Implement robust error handling to gracefully handle API errors and provide a seamless user experience.

  5. Environment Variables: Store your Contentful space ID and access token as environment variables to keep sensitive information secure.

Rendering Content in Next.js

Creating React Components

To display the content fetched from Contentful in your Next.js application, you'll need to create React components. These components will receive the data as props and present it accordingly. Here's a simple BlogPost component that renders a blog post:

import React from 'react';

const BlogPost = ({ title, body }) => {
  return (
    <div>
      <h1>{title}</h1>
      <p>{body}</p>
    </div>
  );
};

export default BlogPost;

In this example, the BlogPost component expects to receive title and body props, which it then renders within an HTML structure. You can create similar components for other content types, such as products, authors, or categories.

Server-Side Rendering (SSR) vs. Static Site Generation (SSG)

Next.js supports two main rendering strategies: Server-Side Rendering (SSR) and Static Site Generation (SSG). The choice depends on your application's requirements and the nature of your content.

Rendering Strategy Description Use Case
Server-Side Rendering (SSR) Content is fetched and rendered on the server for every incoming request. Suitable for frequently updated content or personalized experiences. However, it can lead to increased server load and longer initial load times.
Static Site Generation (SSG) Content is fetched and rendered at build time, resulting in pre-rendered static pages. Ideal for content that doesn't change frequently, such as blog posts or product catalogs. SSG offers improved performance and reduced server load, but may require additional steps for handling dynamic content updates.

Next.js provides built-in functions like getServerSideProps and getStaticProps to handle SSR and SSG, respectively. You can use these functions to fetch data from Contentful and pass it as props to your React components.

Passing Data to Components

After fetching the data from Contentful, you can pass it as props to your React components. Here's an example of how to use getStaticProps to fetch blog posts and pass them to a BlogList component:

import React from 'react';
import { getBlogs } from '../utils/contentfulClient';
import BlogPost from '../components/BlogPost';

const BlogList = ({ blogs }) => {
  return (
    <div>
      {blogs.map((blog) => (
        <BlogPost key={blog.id} title={blog.title} body={blog.body} />
      ))}
    </div>
  );
};

export async function getStaticProps() {
  const blogs = await getBlogs();
  return {
    props: {
      blogs,
    },
  };
}

export default BlogList;

In this example, the getStaticProps function fetches the blog posts from Contentful using the getBlogs utility function. The fetched data is then passed as props to the BlogList component, which renders a list of BlogPost components with the corresponding data.

You can follow a similar approach for other content types and rendering strategies (SSR or SSG) based on your application's requirements.

Advanced Topics

Implementing Pagination

To handle large datasets from Contentful, you can implement pagination in your Next.js application. This involves fetching data in smaller chunks or pages, improving performance and reducing the load on both the client and server.

1. Determine the maximum number of items to fetch per page (e.g., 10, 20, etc.).

2. In your API call to Contentful, use the skip and limit parameters to fetch the desired page of data.

3. Render the fetched data in your component, along with pagination controls (e.g., "Previous" and "Next" buttons).

4. When the user interacts with the pagination controls, update the skip and limit values and fetch the new page of data.

// Fetch data with pagination
const fetchData = async (skip, limit) => {
  const response = await client.getEntries({
    content_type: 'blogPost',
    skip,
    limit,
  });
  return response.items;
};

// In your component
const [posts, setPosts] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(0);

useEffect(() => {
  const fetchPosts = async () => {
    const skip = (currentPage - 1) * 10; // Assuming 10 items per page
    const limit = 10;
    const data = await fetchData(skip, limit);
    setPosts(data);
    setTotalPages(Math.ceil(data.total / limit));
  };
  fetchPosts();
}, [currentPage]);

// Render pagination controls and posts

This approach ensures that your application only fetches and renders the necessary data, improving performance and user experience.

Handling Content Updates

When content in Contentful is updated, you'll need to ensure that your Next.js application displays the latest changes. Here are some ways to achieve this:

  1. Incremental Static Regeneration (ISR): Next.js allows you to use the revalidate option in getStaticProps to periodically regenerate static pages after a specified period (in seconds). This ensures that your application fetches the latest content from Contentful at regular intervals.

  2. Webhooks: Contentful provides webhooks that can notify your application when content changes. You can set up a webhook in Contentful to trigger a rebuild or cache invalidation process in your Next.js application.

  3. Polling: Alternatively, you can implement a polling mechanism in your Next.js application to periodically check for content updates from Contentful and invalidate the cache or trigger a rebuild when changes are detected.

Using Content Preview API

Contentful provides a Content Preview API that allows you to preview unpublished content in your Next.js application. This is useful for content editors and developers who need to review changes before publishing.

  1. Obtain a preview access token from your Contentful space settings.

  2. In your Next.js application, create a separate API route or function to fetch data using the Content Preview API and the preview access token.

  3. Implement a way for content editors to trigger the preview mode in your application (e.g., a preview button or URL parameter).

  4. When preview mode is activated, use the separate API route or function to fetch and render the unpublished content from Contentful.

// pages/api/preview.js
export default async function handler(req, res) {
  const previewAccessToken = process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN;
  const client = createClient({
    space: process.env.CONTENTFUL_SPACE_ID,
    accessToken: previewAccessToken,
    host: 'preview.contentful.com',
  });

  // Fetch preview data from Contentful
  const data = await client.getEntries({ content_type: 'blogPost' });

  // Render the preview data in your Next.js application
  res.setPreviewData({ data });
  res.redirect(`/`);
}

This approach allows content editors to preview unpublished changes before making them live, ensuring a smooth and error-free publishing process.

Performance Optimization

To optimize the performance of your Next.js application when integrating with Contentful, consider the following techniques:

Technique Description
Code Splitting Next.js automatically code-splits your application, ensuring that only the necessary JavaScript is loaded for each page. This reduces the initial load time and improves performance.
Image Optimization Use Next.js's built-in Image component to automatically optimize images for different screen sizes and resolutions. This reduces the bandwidth required and speeds up page loading times.
Caching Implement caching strategies at various levels, such as the browser cache, server cache, and Contentful's built-in caching system. This reduces the load on both the client and server, improving overall performance.
Lazy Loading Utilize lazy loading techniques to load components or resources only when they are needed, reducing the initial load time and improving perceived performance.
Server-Side Rendering (SSR) and Static Site Generation (SSG) Leverage Next.js's SSR and SSG capabilities to pre-render pages on the server or at build time, improving initial load times and ensuring that content is immediately available to users and search engines.
API Optimization When fetching data from Contentful, optimize your API queries by selecting only the fields you need and using pagination to limit the amount of data transferred.

Deploying and Hosting Your Application

Deploying to Vercel or Netlify

Vercel

Deploying your Next.js application integrated with Contentful is simple with platforms like Vercel and Netlify. Both platforms seamlessly integrate with Git repositories and support automatic builds and deployments on every commit.

To deploy your application:

  1. Create a Git repository: If you haven't already, create a new Git repository for your Next.js project and push your code.

  2. Connect to Vercel/Netlify: Sign up for a Vercel or Netlify account and connect your Git repository.

  3. Configure Build Settings: In your project settings, configure the build command and output directory based on your Next.js setup. For most projects, the build command is npm run build or yarn build, and the output directory is .next.

  4. Set Environment Variables: Add your Contentful API keys and other required environment variables to the project settings. These variables will be securely stored and injected into your application during the build process.

  5. Deploy: Trigger a new deployment by committing changes to your Git repository. Vercel and Netlify will automatically detect the changes, build your application, and deploy it to a unique URL.

Using Environment Variables

To securely store and access sensitive information like API keys and tokens, use environment variables.

  1. Vercel: In your project settings, navigate to the "Environment Variables" section and add your Contentful API keys and other sensitive information as key-value pairs.

  2. Netlify: In your project settings, navigate to "Site Settings" > "Build & Deploy" > "Environment" and add your environment variables.

In your Next.js application, access these variables using process.env.<VARIABLE_NAME>. For example:

const client = createClient({
  space: process.env.CONTENTFUL_SPACE_ID,
  accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
});

Setting Up CI/CD

Continuous Integration and Continuous Deployment (CI/CD) can streamline your development workflow by automatically building and deploying your application whenever changes are made to your codebase.

Both Vercel and Netlify offer built-in CI/CD capabilities, allowing you to set up automated builds and deployments directly from your Git repository.

  1. Vercel: Vercel automatically sets up CI/CD for your project when you connect your Git repository. Every time you push changes, Vercel will trigger a new build and deployment.

  2. Netlify: Netlify also supports automatic builds and deployments from your Git repository. In your project settings, navigate to the "Build & Deploy" section and configure the build settings and deployment branch.

With CI/CD in place, your Next.js application integrated with Contentful will always be up-to-date and deployed with the latest changes, streamlining your development and deployment workflow.

Conclusion

Combining Contentful, a powerful headless CMS, with Next.js offers a flexible and scalable solution for building modern web applications. By leveraging Contentful's API-first approach and Next.js's server-side rendering capabilities, you can create high-performance, SEO-friendly websites and web apps.

This guide covered the essential steps to:

  • Set up a Next.js project

  • Configure Contentful

  • Fetch and render content using the Contentful REST API

  • Deploy your application

By following these steps, you can unlock the benefits of a headless CMS while taking advantage of Next.js's features, such as static site generation and server-side rendering.

To further enhance your Next.js and Contentful integration, explore:

Advanced Topic Description
Content Previewing Preview unpublished content before publishing
Performance Optimization Techniques like code splitting, image optimization, and caching
Pagination Fetch and display large datasets in smaller chunks
Real-time Content Updates Ensure your application displays the latest content changes

Additionally, consider leveraging Contentful's GraphQL API for more complex querying and data fetching scenarios.

For more resources and guidance, refer to the official documentation from Contentful and Next.js, as well as their developer communities.

Related posts