Unleashing the Power of Headless CMS: Building Modern Web Applications with Next.js and Strapi

Web development technologies are evolving at a rapid pace, and there is no shortage of options for front-end and back-end development. Full-stack frameworks like Vue.js and Django provide a comprehensive suite of tools to build modern web applications, but sometimes the best solution is to combine specialized tools to create highly efficient and flexible workflows. Headless CMS like Strapi offer developers the freedom to focus on front-end development and user experience, while Next.js provides static and dynamic rendering options that help create highly performant web applications. In this tutorial, we will walk you through the process of building a sample web application using Next.js and Strapi, and explore the many possibilities of headless CMS and modern web development.

Why Use Headless CMS?

Headless content management systems, or headless CMS, decouple the content creation and management process from the front-end presentation of the content. In traditional CMS, the content creation functionality is tightly coupled with the presentation layer, making it difficult to reuse content across multiple platforms and formats. With headless CMS, developers can retrieve content as APIs and integrate it with a wide range of front-end development frameworks without being restricted by the CMS's presentation layer.

Strapi is a highly flexible and scalable headless CMS built with Node.js. It offers a wide range of features and functionalities, including custom fields, role-based access control, and easy deployment with Docker and Kubernetes. Strapi also provides a highly customizable admin panel that allows non-technical content creators to easily manage content without relying on front-end developers.

What is Next.js?

Next.js is a popular open-source framework for building server-side rendered (SSR) and static web applications using React components. Next.js provides a suite of optimized tools for building highly performant applications, including automatic code splitting, serverless functions via API routes, and fast static exporting via the `next export` command. Next.js also has excellent static optimization features, making it simple to build SEO-friendly pages without overcomplicating the build process.

When combined with Strapi, developers can build highly scalable and optimized web applications that offer a wide range of cutting-edge features and functionalities. Here's how to do it.

Building a Sample Web Application with Next.js and Strapi

To follow along, you'll need a basic knowledge of JavaScript, React, and Node.js. You'll also need to have the latest version of Node.js and NPM installed on your machine.

Step 1: Create a New Next.js Application

To create a new Next.js application, run the following command in your terminal:

npx create-next-app my-app

This command will create a new Next.js application named `my-app`. Next, navigate to the newly created directory and start the development server:

cd my-app && npm run dev

This command starts a development server on `localhost:3000`. You should see a sample Next.js application running on your local machine. Next, open http://localhost:3000 in your web browser.

Step 2: Create a Strapi Instance

To create a Strapi instance, run the following command in a new terminal window:

npx create-strapi-app my-strapi-app --quickstart

This command will create a new Strapi instance named `my-strapi-app`. Strapi will automatically create a PostgreSQL database and configure a simple content model with two fields: title and description. Next, navigate to the Strapi directory and start the server:

cd my-strapi-app && npm run develop

This command will start a development server on `localhost:1337`. You should see a default Strapi admin panel at http://localhost:1337/admin.

Step 3: Create a New Collection Type in Strapi

In this step, we'll create a new collection type in Strapi to store our sample data. From the main Strapi admin screen, click on the `Collection Types` menu option on the left-hand side. Next, click on the `Create new Collection Type` button.

In the `Collection Type name` field, enter `Article`. In the `Displayed name` field, enter `Articles`. Next, click on the `Add another field` button to add new fields to the collection. In the `Name` field, enter `title` and select `Text` as the `Type`. In the `Name` field for the second field, enter `description` and select `Text` as the `Type`. Finally, click on the `Save` button to create the new collection type.

Step 4: Create Some Sample Data in Strapi

Now that we have a collection type, we need to populate it with some sample data. From the main Strapi admin screen, click on the `Articles` menu option on the left-hand side to navigate to the new collection type. Click on the `Add new Article` button to create a new article.

In the new article form, enter a title and description for the article. Click on the `Save` button to create the new article. You can repeat this step to create additional articles with different titles and descriptions.

Step 5: Connect Next.js with Strapi

Now that we have a sample Next.js application and a Strapi instance with sample data, let's connect the two. First, install the `@apollo/client` package:

npm install @apollo/client graphql

Next, create a new file named `apolloClient.js` in your Next.js application's `utils` folder. Add the following code to this file:

      import { ApolloClient, InMemoryCache } from '@apollo/client';

      export const client = new ApolloClient({
        uri: 'http://localhost:1337/graphql',
        cache: new InMemoryCache()

This code creates an instance of the `ApolloClient` class and sets the `uri` property to the GraphQL endpoint of our Strapi instance. Next, open the `_app.js` file in your Next.js application's `pages` folder. Add the following imports to the top of the file:

      import { ApolloProvider } from '@apollo/client';
      import { client } from '../utils/apolloClient';

This code imports the `ApolloProvider` component and the `client` from our `apolloClient.js` file. Next, wrap the `MyApp` component in the `ApolloProvider` component, like so:

      export default function MyApp({ Component, pageProps }) {
        return (
          <ApolloProvider client={client}>
            <Component {...pageProps} />

This code makes the `client` available to all components wrapped by the `ApolloProvider`, enabling us to connect to the Strapi instance from anywhere in our application. Next, create a new file named `index.js` in your Next.js application's `pages` folder. Add the following code to this file:

      import { useQuery, gql } from '@apollo/client';

      export const GET_ARTICLES = gql`
        query Articles {
          articles {

      export default function Home() {
        const { loading, error, data } = useQuery(GET_ARTICLES);

        if (loading) return 


; if (error) return


; return ( <div> {data.articles.map(article => ( <div key={article.id}> <h2>{article.title}</h2> <p>{article.description}</p> </div> ))} </div> ); }

This code defines a GraphQL query to retrieve the articles from our Strapi instance. We use the `useQuery` hook from the `@apollo/client` package to execute the query and retrieve the articles. Finally, we render the articles as a list of titles and descriptions.

To view the results, refresh your browser at http://localhost:3000/. You should see a list of titles and descriptions of your sample articles loaded from your Strapi instance.


Headless CMS like Strapi offer developers the freedom to build highly customized and scalable web applications without being constrained by the restrictions of traditional CMS. By combining Strapi with Next.js, you can build highly performant web applications with dynamic and static rendering capabilities that provide a seamless user experience across multiple platforms. We hope this tutorial has given you a glimpse into the many possibilities of modern web development, and inspired you to explore and experiment with the latest tools and technologies available to developers today.