Using WordPress as a Headless CMS with Next.js: What Nobody Tells You
Decoupling WordPress from its frontend and replacing it with Next.js sounds clean on paper. In practice, there are a dozen sharp edges — from custom plugins to sitemap surgery — that catch most teams off guard.
Using WordPress as a Headless CMS with Next.js: What Nobody Tells You
The pitch for going headless with WordPress sounds compelling: keep the familiar content management interface your team already knows, swap out the creaking PHP-rendered frontend for a fast, modern Next.js application, and get the best of both worlds. A polished React front end. A mature CMS back end. Clean separation of concerns.
The reality is more complicated. Not impossible — we've delivered successful headless WordPress + Next.js projects for Sydney businesses — but there's a long list of things that need deliberate attention that most articles on the subject gloss over. This piece covers the real friction points, why they exist, and how to handle them properly.
Is Headless WordPress Actually Worth It for Your Business?
Before getting into implementation, it's worth asking whether this architecture makes sense for your situation at all.
Headless WordPress adds genuine value when:
- You need performance that a standard WordPress theme can't deliver (Core Web Vitals are critical for your SEO or conversions)
- You're building a complex application-like experience on the front end — dynamic filtering, real-time data, personalisation
- You're publishing content that needs to be delivered across multiple channels simultaneously (web, mobile app, digital signage, etc.)
- Your development team already works in React/TypeScript and maintaining a PHP theme stack is a drag on productivity
It's probably not worth the overhead when:
- You have a standard brochure site or blog where a well-configured WordPress theme with a CDN would perform adequately
- Your team doesn't have strong JavaScript/React capability in-house
- You're on a tight budget — headless architectures cost more to build and more to host than a straightforward WordPress site
For a business with a content-heavy site, a team comfortable in modern JavaScript, and genuine performance requirements, the tradeoff is worth it. For everyone else, it often introduces complexity without proportionate benefit.
The Custom Plugin Problem
The first thing that breaks when you decouple WordPress is every piece of functionality that assumed the theme and the CMS were in the same process.
Contact forms, custom post type fields, SEO metadata, breadcrumbs, related content, custom taxonomies with complex relationships — all of these are handled by WordPress plugins that write output to the PHP-rendered page. In a headless setup, there is no PHP-rendered page on the public side. The plugin output goes nowhere.
You have two options: find a plugin that exposes its data through the WordPress REST API or WPGraphQL, or build a custom plugin that does it yourself.
WPGraphQL is the better path for most projects. It exposes WordPress content as a GraphQL API, and many popular plugins (ACF, Yoast, WPML) have WPGraphQL extensions. But not all plugins do, and the ones that don't require custom work.
Custom plugin development is where most headless WordPress projects accumulate hidden cost. You'll typically need to write at least one custom plugin that:
- Registers REST API or GraphQL endpoints for any custom post types or fields not already exposed
- Returns structured data in a shape your Next.js application can consume cleanly — not the raw WordPress format, which is often inconsistent
- Handles authentication if any content is gated or user-specific
- Exposes preview content for draft posts, which requires a separate authenticated endpoint
None of this is architecturally complex, but it's all work that doesn't exist in a traditional WordPress build, and it needs to be maintained when plugins update and change their data structures.
Replicating WordPress Behaviour That You Took for Granted
WordPress handles a surprising amount of behaviour automatically that you'll need to explicitly rebuild in Next.js.
Routing. WordPress generates URLs from your post/page structure automatically. In Next.js, you need to generate routes statically at build time (using getStaticPaths) or dynamically at request time (using getServerSideProps or the App Router equivalent). For sites with hundreds or thousands of posts, getting this right — including handling category and tag archives, author pages, pagination, and custom post type archives — requires deliberate mapping between the WordPress permalink structure and your Next.js route definitions.
Images. WordPress generates multiple image sizes automatically on upload and handles srcset attributes in the output HTML. In Next.js, you'll use next/image for optimisation, but you need to configure your WordPress media domain as a remote image source and decide how to pass the available size variants through your API responses. If your content contains images embedded in post body HTML (from the block editor or classic editor), those images need separate handling — you either parse and rewrite the HTML server-side or process it in the component with a library like html-react-parser.
Shortcodes and blocks. If your WordPress content uses Gutenberg blocks or legacy shortcodes, the raw HTML you get back from the API contains block comment delimiters and sometimes PHP shortcode syntax. You need a strategy for each: either strip/ignore them, replace them with React components, or ensure your content authors avoid them entirely in the headless context.
Redirects. WordPress handles URL redirects through its rewrite rules or plugins like Redirection. In a headless setup, redirects need to live in your Next.js layer — in next.config.js for static redirects or a middleware function for dynamic ones. If you're migrating from an existing WordPress site, exporting and importing the existing redirect table is a task that's easy to forget and costly to discover missing after go-live.
The Sitemap Problem — and How to Fix It
This is the one that causes the most damage to organic search performance on headless migrations, and it's almost always handled badly.
Standard WordPress generates a sitemap automatically via plugins like Yoast or Rank Math. When you go headless, that sitemap still exists and still reflects WordPress URLs. But your Next.js frontend is serving the content on a different domain or origin. If you don't handle this carefully, Google ends up indexing the wrong URLs — or receiving contradictory signals from two sitemaps pointing at the same content served in two different ways.
The correct approach:
Generate your sitemap from Next.js, not WordPress. The sitemap your users and search engines access should come from your Next.js application — it should reflect the URLs that are actually being served to users. Next.js 13+ has a built-in sitemap.ts convention in the App Router that makes this straightforward. Alternatively, a route handler that dynamically fetches all published content from the WordPress API and returns a properly formatted XML sitemap works well and ensures the sitemap is always current.
Disable or redirect the WordPress sitemap. The WordPress-generated sitemap at /sitemap.xml needs to be either disabled or redirected to your canonical sitemap. Leaving it active creates a second authoritative-looking sitemap pointing at wp-admin domain URLs. If those URLs are publicly accessible (which they usually are — WordPress doesn't block its own frontend by default), Google will index both sets of URLs as separate content and dilute your authority.
Handle canonical URLs explicitly. Every page your Next.js app renders needs a canonical meta tag pointing at the public-facing URL. This seems obvious, but in practice it's easy to get wrong when your development environment, staging environment, and production environment all have different domain configurations. Parameterise your base URL from an environment variable and verify it at each stage.
Block the WordPress frontend. If your WordPress instance is hosted on a subdomain or separate domain (e.g. cms.yourdomain.com.au), use a noindex header on the WordPress frontend or robots.txt disallow to prevent Google indexing the CMS layer directly. You want exactly one set of canonical URLs — the ones your Next.js app serves.
Preserve existing URL structures during migration. If you're migrating a live WordPress site that already has Google-indexed URLs, your Next.js routing must produce identical URLs. Changing /services/web-design/ to /services/web-design (dropping the trailing slash, or changing slug format) creates unnecessary redirect chains and temporarily tanks rankings. Audit your existing URL structure before writing a single route.
Handling SEO Metadata
WordPress SEO plugins like Yoast or Rank Math store per-post SEO metadata — custom title, meta description, canonical, Open Graph image, robots directives — in post meta fields. This data needs to be explicitly exposed through your API and consumed by your Next.js application.
WPGraphQL SEO (the WPGraphQL extension for Yoast) handles this cleanly. You query the seo field on any post or page and get back structured metadata you can write directly into your <Head> component or Next.js Metadata API object.
If you're not using WPGraphQL, you'll need a custom REST API endpoint that returns the SEO fields for each post, or you'll end up maintaining SEO metadata in two places — once in WordPress and once hardcoded in your Next.js components.
Preview Mode
Content authors expect to be able to preview unpublished content before it goes live. WordPress preview works by generating a temporary URL that renders the draft version of a post. In a headless setup, that preview URL points at the WordPress frontend — which no longer exists in production.
Next.js has a Draft Mode (previously called Preview Mode) designed exactly for this. The flow is:
- Configure a WordPress plugin to redirect preview clicks to a Next.js preview API route
- The API route validates the request (using a shared secret), enables Draft Mode, and redirects to the content URL
- Next.js, when in Draft Mode, fetches draft content from WordPress rather than published content
- Draft Mode is cleared when the author closes the preview
Setting this up correctly requires the custom WordPress plugin work mentioned earlier — specifically, a plugin that intercepts the preview redirect and sends it to your Next.js application rather than the WordPress frontend.
Build Times and Content at Scale
Static site generation in Next.js means your content is built into HTML at deploy time. For a site with twenty pages, that's trivial. For a site with a thousand posts, each requiring a WordPress API call to fetch its content, that's a multi-minute build for every content update.
The solutions are incremental static regeneration (ISR) — where Next.js rebuilds individual pages on-demand after a revalidation period — or on-demand revalidation triggered by a WordPress webhook when a post is published or updated. ISR with on-demand revalidation is the right architecture for most content-heavy headless WordPress projects: pages are served statically for speed, but go stale only in the window between publish and the webhook-triggered revalidation (typically seconds).
Worth It When Done Right
A headless WordPress + Next.js stack, built properly, performs better, is easier to maintain from a frontend developer's perspective, and unlocks capabilities that a traditional WordPress theme can't match. But "built properly" requires confronting the sharp edges described above — not just building the happy path and hoping the rest sorts itself out.
At Proanalytica Technologies, we've handled the plugin work, the sitemap architecture, the preview configuration, and the SEO migration for Sydney businesses making this transition. If you're evaluating a headless rebuild or partway through one that's run into these issues, get in touch — it's usually fixable.
Jayden Lee
Founder of Proanalytica Technologies. Machine learning engineer and software developer based in Sydney, NSW. Helping Greater Sydney small businesses build better digital infrastructure.
Need help with your Sydney business?
From web design and WordPress maintenance to ServiceM8 setup and AI automation — we work with Greater Sydney SMBs.
Get in Touch