Home / Blog / Headless WordPress migration: the path to a 35% speed lift

Headless WordPress migration: the path to a 35% speed lift

A six-month migration from traditional WP to headless (WP backend plus Next.js frontend). How much speed, how much complexity?

Headless WordPress has been popular for two or three years. WordPress’s content management strength paired with modern frontend performance. But a headless migration is not as light as most posts claim. Here’s what I learned from a six-month migration project.

Project context

Client: B2C brand, a million visits a month, WordPress plus WooCommerce. Problems:

  • High TTFB (1.2 to 1.8 seconds)
  • Plugin weight (18 active plugins)
  • Theme complexity (25K LOC custom theme)
  • Poor mobile Core Web Vitals

Choice: headless migration. WP content on the backend, Next.js on the frontend.

Target architecture

[CMS Editor] → WordPress (headless, no theme)
                    ↓ (WP REST API)
               [Next.js frontend]
                    ↓ (ISR/SSG)
                 [CDN edge]
                    ↓
                [End user]

WP is a pure content repository. Next.js fetches at build time, generates static pages, and uses ISR (Incremental Static Regeneration) to refresh periodically.

Order and checkout remain on the WP side (WooCommerce); only product listings, blog, and static pages live on Next.js.

First phase: prepping WP

The WP frontend will be unused, but the backend is still active. Changes:

1. Trim the custom theme. No frontend rendering, only admin and REST API. wp_head/wp_footer cleared, scripts and styles no longer enqueued.

2. Plugin audit. Anything that affects the frontend (caching, SEO frontend, UI widgets) comes off. Backend plugins (ACF, WooCommerce admin, WPML) stay.

3. REST API extensions. The default /wp-json/wp/v2/* endpoints aren’t enough; custom fields need exposure.

add_action('rest_api_init', function() {
    register_rest_field('post', 'acf_data', [
        'get_callback' => function($post) {
            return get_fields($post['id']);
        }
    ]);
});

Or reach for the WPGraphQL plugin for a GraphQL endpoint.

4. Preview. Editors want to see drafts. A preview mode endpoint on Next.js plus a “Preview” button in WP that redirects to the Next.js URL.

REST vs GraphQL

Two ways to do headless WP:

REST API (built-in):
– Pros: zero setup, native WP
– Cons: over-fetching, multiple requests, no field selection

WPGraphQL (plugin):
– Pros: single request, field selection, type safety
– Cons: plugin dependency, learning curve, the occasional edge case

I picked GraphQL for this project. Frontend pulls the entire page’s data in one request (product plus category plus related plus meta); REST would’ve been four or five round trips.

The Next.js side

Build strategy: SSG plus ISR.

Product detail pages statically generate at build time. When a product updates, ISR refreshes it within 60 seconds.

export async function getStaticProps({ params }) {
    const product = await fetchProduct(params.slug);
    return {
        props: { product },
        revalidate: 60  // ISR: 60 seconds
    };
}

export async function getStaticPaths() {
    const slugs = await fetchPopularProductSlugs(1000);
    return {
        paths: slugs.map(slug => ({ params: { slug } })),
        fallback: 'blocking'
    };
}

The top 1,000 products are generated at build, everything else is on-demand fallback.

Image optimisation. Next.js <Image> handles it automatically. Images from the WP media library are referenced by URL; Next.js resizes and optimises at the edge.

CSS approach. Tailwind plus component-scoped CSS. None of the WP theme’s CSS comes across; we design fresh.

Deployment

WordPress stays on the VPS. Next.js runs on Vercel (or your own host). Two deployments.

Content update → WP admin → WP REST/GraphQL reflects it → Next.js ISR revalidation triggers → CDN cache purge → user refreshes and sees the update.

Revalidation webhook:

add_action('save_post', function($post_id) {
    wp_remote_post('https://nextjs-site.com/api/revalidate', [
        'body' => ['slug' => get_post_field('post_name', $post_id)]
    ]);
});

Next.js endpoint:

export async function POST(request) {
    const { slug } = await request.json();
    await revalidatePath(`/product/${slug}`);
    return Response.json({ revalidated: true });
}

WooCommerce integration

WooCommerce checkout doesn’t migrate to Next.js. Too complex, too much compliance risk. Two-site approach:

  • Product listing and detail: Next.js
  • Cart, checkout, account: WordPress (native WC)
  • “Add to cart” POSTs to the WC AJAX endpoint, cart fragment updates

The experience feels fluid, but running two systems is maintenance burden.

Alternative: adopt headless commerce on the Next.js side (BigCommerce, Shopify Hydrogen) and leave WooCommerce behind. Too big a scope for this project.

Performance: before vs after

Before:
– TTFB: 1.4s average
– LCP p75 (mobile): 3.8s
– CLS p75: 0.15
– Lighthouse Performance: 52

After (six months in):
– TTFB: 120ms (CDN edge)
– LCP p75 (mobile): 2.4s
– CLS p75: 0.05
– Lighthouse Performance: 87

LCP improved 37%, TTFB was a step change. Core Web Vitals in the green.

Hidden costs of the migration

1. Dual-system maintenance. WP admin plus Next.js frontend means two codebases, two deployments, two monitoring setups.

2. Editor workflow. Editors have to get used to the Next.js preview. WP’s “preview” no longer shows the frontend directly, it fetches from Next.js.

3. Third-party integration. Gravity Forms, newsletter plugins that worked on the frontend have to move to Next.js or be called via API.

4. SEO migration. Yoast’s output has to be manually ported to Next.js. The yoast_head_json REST field helps, but migrating all schema markup is work.

5. A/B testing, analytics. GTM, Hotjar, Google Analytics have to be set up from scratch. No plugins handle it for you.

6. Build time. 1,000 products take five to ten minutes to build. CI iteration slows. ISR solves it in production, but dev experience suffers.

When headless doesn’t make sense

  • WordPress blog only, no WooCommerce: overkill. Native WP plus caching is enough.
  • Team is a single PHP developer: the frontend stack is extra weight.
  • Low traffic (under 100K visits/month): the perf gain is marginal.
  • Editors uncomfortable with workflow change: risk.
  • Plugin-heavy site (20+ frontend plugins): everything has to be migrated or abandoned.

When headless makes sense

  • Performance is critical (e-commerce, news, high-traffic)
  • Dev team likes React or Next.js
  • You need rich frontend interactivity (app-like UX)
  • Heavy A/B testing or personalisation
  • Multi-channel (web plus mobile app sharing one API)

Assessing six months in

The client is happy. Performance is better, conversion rate is up 8%, mobile bounce is down 15%.

But the maintenance burden is higher: the team needs both Next.js and WP skills. Small content edits are still easy (WP admin), but feature work lives in two places.

Implementation cost landed around $70K, migration took six months. ROI projection was positive at 18 months.

Closing thought

Headless WordPress isn’t a silver bullet. Chasing the hype is risky. Ask first:

  • Have you exhausted traditional WP optimisation? (caching, CDN, plugin audit)
  • Do you have frontend dev capacity?
  • Can you absorb the maintenance burden?

“Yes” to all three makes headless meaningful. Otherwise, traditional WP plus proper optimisation covers most cases. A 35% improvement isn’t worth six months and a big cheque for every project.

Have a project on this topic?

Leave a brief summary — I’ll get back to you within 24 hours.

Get in touch