In today’s rapidly evolving web development landscape, combining the powerful content management features of WordPress with the modern performance benefits of React frameworks like Next.js has become a popular approach. For developers who want a blazing-fast frontend while leveraging WordPress as a backend CMS, a headless architecture is the ultimate solution. The release of Next.js 14 brings even more flexibility and features with the introduction of the App Router. This article details how to create a fully functional headless WordPress blog using Next.js 14 with the App Router, fetching data through WordPress’s REST API.
What is a Headless WordPress Setup?
A headless WordPress site refers to a setup where WordPress is used strictly as the backend – a source of data – while the frontend is powered by an external framework, in this case, Next.js. Instead of rendering pages using PHP templates, the frontend fetches WordPress content via the REST API or GraphQL and displays it in a React-based UI. This leads to:
- Enhanced performance and SEO using static generation or server-side rendering.
- Greater flexibility in designing UI with modern JavaScript frameworks.
- Separation of concerns, making it easier to scale or change the frontend without affecting the backend.
Why Use Next.js 14 and the App Router?
Next.js 14 builds on the composability and performance edge of previous versions, but with improved routing, loading states, and enhanced server functionality through the App Router. The App Router introduces a file-based routing system under the app directory and better support for layouts, data fetching, and abstraction.
- Layouts & Templates: Share common UI across pages effortlessly.
- Server Components: Load components on the server for improved rendering.
- Streaming: Send pages to the user in pieces while the full UI loads progressively.
Step-by-Step Guide to Create a Headless WordPress Blog
1. Set Up the WordPress Backend
Start by installing a basic WordPress site on a server or locally using tools like XAMPP, LocalWP, or Docker. Ensure that the REST API is enabled (it is by default in WordPress 4.7+).
To get blog post data, you can access endpoints like:
https://yourdomain.com/wp-json/wp/v2/posts
Optionally, install plugins for extended functionality:
- JWT Authentication: Secure API access.
- ACF (Advanced Custom Fields): Add custom fields to your content.
- WPGraphQL: If you prefer GraphQL over REST.
2. Initialize Your Next.js 14 Project
Ensure Node.js is installed, then run:
npx create-next-app@latest headless-blog --experimental-app
This will scaffold a new Next.js 14 app with the App Router enabled. Navigate to the new directory:
cd headless-blog
3. Set Up the App Directory Structure
Within the new Next.js 14 setup, you’ll use the app/ folder for routing and page generation. Create a layout with:
app/ ├─ layout.tsx ├─ page.tsx ├─ blog/ │ ├─ page.tsx │ └─ [slug]/ │ └─ page.tsx
layout.tsx serves as a wrapper for persistent elements like the header or footer. blog/page.tsx lists all blog posts, and blog/[slug]/page.tsx handles individual blog post pages.
4. Fetching Content from the WordPress REST API
Use the built-in fetch API in Server Components to retrieve data from your WordPress site. For instance, to get posts in blog/page.tsx:
async function getPosts() { const res = await fetch('https://yourdomain.com/wp-json/wp/v2/posts'); if (!res.ok) throw new Error('Failed to fetch posts'); return res.json(); } export default async function BlogPage() { const posts = await getPosts(); return ( <div> <h1>Latest Posts</h1> <ul> {posts.map((post) => ( <li key={post.id}> <a href={`/blog/${post.slug}`}>{post.title.rendered}</a> </li> ))} </ul> </div> ); }
5. Dynamic Routing for Single Post Pages
Inside blog/[slug]/page.tsx, fetch each post using the slug:
async function getPost(slug) { const res = await fetch(`https://yourdomain.com/wp-json/wp/v2/posts?slug=${slug}`); const data = await res.json(); return data[0]; } export default async function PostPage({ params }) { const post = await getPost(params.slug); return ( <article> <h1>{post.title.rendered}</h1> <div dangerouslySetInnerHTML={{ __html: post.content.rendered }} /> </article> ); }
This queries WordPress for content by slug and renders it statically or via ISR (Incremental Static Regeneration).

6. Styling and Theming
Use CSS modules or Tailwind CSS to style your blog. To add Tailwind, run:
npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p
Then update the tailwind.config.js and include Tailwind in your global CSS file. Components can then be styled using Tailwind classes for a rapid and responsive layout.
7. Deployment and Hosting
When you’re ready to go live, deploy the app on Vercel, the creators of Next.js:
- Push your code to GitHub.
- Login to Vercel and import your repo.
- Configure environment variables for WordPress API URLs.
Vercel automatically detects it’s a Next.js app and optimizes for serverless deployment with caching and ISR built-in.
Conclusion
By using Next.js 14 and the App Router, developers can build a modern, high-performance frontend for a WordPress backend. This architecture not only separates concerns but significantly improves loading speed, scalability, and maintainability. The flexibility of React combined with WordPress’s content infrastructure makes this a powerful tech stack for blogs, portfolios, and content-heavy sites.
Frequently Asked Questions (FAQ)
-
Q: Do I need to install additional plugins in WordPress for REST API access?
A: No, the WordPress REST API is enabled by default in versions 4.7 and up. However, you may need plugins for authentication or custom fields. -
Q: Can I use GraphQL instead of REST?
A: Yes, by installing the WPGraphQL plugin, you can query your content using GraphQL, which many developers find more flexible and intuitive. -
Q: Is Next.js 14 backward compatible with older versions?
A: Yes, generally. But if you switch to the App Router and Server Components, you should follow the new folder structure and routing APIs explicitly. -
Q: Is it possible to preview draft posts from WordPress in the frontend?
A: Yes, but it requires authentication. Use JWT or cookie-based auth from Next.js to securely fetch drafts via the API. -
Q: How do I handle pagination?
A: Use the page and per_page parameters in the REST API, and implement pagination logic on your frontend using query parameters.