Building a Headless CMS with WordPress and Next.js (With Full Code Examples)

Building a Headless CMS with WordPress and Next.js (With Full Code Examples)

In modern web development, Headless CMS architecture has gained massive popularity due to its flexibility, scalability, and performance benefits. Among various options, using WordPress as Headless CMS combined with a powerful frontend framework like Next.js provides a perfect balance between a robust backend and a blazing-fast frontend.

In this blog, we will walk through:

  • Why use WordPress as Headless CMS
  • Why it’s important to adapt this approach
  • Setup WordPress for Headless
  • Setup Next.js to consume WordPress data
  • Complete code examples for fetching and rendering content
  • Deployment tips

Why It’s Important to Adapt Headless WordPress with Next.js Today

The requirements and expectations from modern web applications have evolved rapidly. Here’s why adapting this architecture is crucial in 2025 and beyond:

  • Omnichannel Content Delivery: Users access content on multiple devices – web, mobile apps, smart TVs, and even IoT devices. Headless CMS allows you to deliver content seamlessly across all these platforms.
  • Better Performance & SEO: Next.js offers server-side rendering (SSR), static site generation (SSG), and incremental static regeneration (ISR). This leads to faster load times, better SEO rankings, and improved Core Web Vitals scores.
  • Developer Productivity: Developers can work independently on the frontend without being tied to backend systems. Teams can specialize and scale better.
  • Security & Scalability: Decoupling the frontend from the backend minimizes the attack surface. WordPress is no longer directly exposed to public traffic.
  • Modern UI/UX Expectations: Users expect highly interactive and dynamic interfaces. React-based frontend frameworks like Next.js allow for richer experiences that traditional WordPress themes can’t deliver.
  • Future-Proof Architecture: Moving to a headless architecture allows businesses to adopt future technologies without a complete rebuild.
  • API-First Ecosystem: With GraphQL and REST APIs, your data becomes portable and can be reused easily across multiple platforms and services.
  • Faster Time-to-Market: Modern development workflows, component-based UI, and reusable APIs mean faster feature development and deployment cycles.

In today’s competitive digital landscape, adopting a headless CMS approach is not just a technical preference, but a business necessity for speed, flexibility, and growth.

Sample Project Repo Structure

headless-wordpress-nextjs/
├── lib/
│   ├── apollo.js
│   └── queries.js
├── pages/
│   ├── index.js
│   └── post/
│       └── [slug].js
├── public/
├── styles/
├── package.json
├── .env.local (for environment variables)
└── README.md

Why Headless WordPress?

WordPress is a battle-tested CMS with a huge ecosystem. By using it as a headless CMS:

  • You retain WordPress’s admin/editor experience.
  • Deliver content via REST API or GraphQL.
  • Build performant frontend using Next.js with SSR, ISR, SSG capabilities.
  • Easier multi-platform content delivery (Web, Mobile, etc.).

Architecture Overview

Step 1 – Setup WordPress as Headless CMS

1. Install WordPress (Locally or Hosted)

You can use:

  • Local WP
  • Docker-based WordPress
  • Hosted WordPress (Kinsta, WP Engine, etc.)

2. Install & Configure Plugins

a) Install “WPGraphQL”

Plugins > Add New > Search "WPGraphQL"

WPGraphQL exposes your WordPress data via GraphQL.

b) (Optional) Install “WPGraphQL JWT Authentication” (for protected routes)

c) (Optional) Install “WPGraphQL Yoast SEO”, “WPGraphQL ACF” for SEO & Custom Fields support.


Step 2 – Setup Next.js Frontend

1. Initialize Next.js Project

npx create-next-app headless-wordpress-nextjs
cd headless-wordpress-nextjs

2. Install Apollo Client for GraphQL

npm install @apollo/client graphql

Step 3 – Connect Next.js with WordPress

1. Create Apollo Client Instance

Create a new file: lib/apollo.js

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

const client = new ApolloClient({
  uri: 'https://your-wordpress-domain.com/graphql',
  cache: new InMemoryCache(),
});

export default client;

Replace https://your-wordpress-domain.com/graphql with your actual WordPress GraphQL endpoint.

2. Create GraphQL Query

Create lib/queries.js

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

export const GET_POSTS = gql
  query GetPosts {
    posts {
      nodes {
        id
        title
        slug
        excerpt
        date
      }
    }
  }
;

export const GET_POST_BY_SLUG = gql
  query GetPostBySlug($slug: ID!) {
    post(id: $slug, idType: SLUG) {
      id
      title
      content
      date
    }
  }
;

3. Fetch Data on Homepage

In pages/index.js:

import client from '../lib/apollo';
import { GET_POSTS } from '../lib/queries';
import Link from 'next/link';

export async function getStaticProps() {
  const { data } = await client.query({ query: GET_POSTS });
  return {
    props: {
      posts: data.posts.nodes,
    },
  };
}

export default function Home({ posts }) {
  return (
    <div className="container mx-auto p-4">
      <h1 className="text-3xl font-bold mb-4">WordPress Headless Blog</h1>
      <ul>
        {posts.map(post => (
          <li key={post.id} className="mb-3">
            <Link href={/post/${post.slug}}>
              <a className="text-xl text-blue-600">{post.title}</a>
            </Link>
          </li>
        ))}
      </ul>
    </div>
  );
}

4. Create Dynamic Post Page

Create pages/post/[slug].js:

import client from '../../lib/apollo';
import { GET_POSTS, GET_POST_BY_SLUG } from '../../lib/queries';
import { useRouter } from 'next/router';

export async function getStaticPaths() {
  const { data } = await client.query({ query: GET_POSTS });
  const paths = data.posts.nodes.map(post => ({
    params: { slug: post.slug },
  }));

  return { paths, fallback: false };
}

export async function getStaticProps({ params }) {
  const { data } = await client.query({
    query: GET_POST_BY_SLUG,
    variables: { slug: params.slug },
  });

  return { props: { post: data.post } };
}

export default function Post({ post }) {
  return (
    <div className="container mx-auto p-4">
      <h1 className="text-3xl font-bold mb-4">{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </div>
  );
}

Step 4 – Deployment Tips

Deploy WordPress Backend

  • WP Engine
  • Kinsta
  • Cloudways
  • Run WordPress behind Cloudflare for better security.

Deploy Next.js Frontend

  • Vercel (best for Next.js)
  • Netlify
  • AWS Amplify

Setup CORS & Security

  • Use proper CORS headers.
  • Secure WordPress GraphQL endpoint with authentication if needed.

Advantages Recap

  • SEO friendly (SSG, SSR in Next.js)
  • Blazing-fast frontend
  • Scalable architecture
  • Multi-platform content reuse
  • Use best of both worlds (WordPress + React)

Summary

  • Use WordPress for content management.
  • Use WPGraphQL to expose WordPress content.
  • Build frontend with Next.js using Apollo Client.
  • Benefit from static generation, server-side rendering, and high SEO performance.
  • Deploy WordPress backend on any managed host; deploy Next.js on Vercel.

Conclusion

Using WordPress as a Headless CMS with Next.js allows you to build enterprise-grade JAMstack apps while leveraging the familiar WordPress admin. With GraphQL APIs, we can easily fetch and render dynamic content with modern React-powered UIs.