← Writing
WordPress to Next.js Migration28 Jul 2026 · 9 min read

How I Moved Mackex from WordPress to a Fast Next.js Site

The goal was not to throw WordPress away. The goal was to stop making WordPress serve the public experience.

Mackex Services is an electrical infrastructure contractor in New South Wales. The website needed to feel credible for a real construction services business, keep content manageable for non-developers, and load quickly on mobile without carrying the usual weight of a theme-heavy WordPress build.

I rebuilt the site as a Next.js App Router frontend, kept WordPress as the content system, connected the two through WPGraphQL, and deployed the public experience on Vercel. The result is a headless WordPress setup: editors can still manage content in WordPress, while visitors receive a faster, cleaner, more controlled frontend.

Direct answer: I converted Mackex from a traditional WordPress website into a Next.js site by using WordPress only as the CMS, reading content through WPGraphQL, pre-rendering public pages with ISR, optimizing images and metadata in Next.js, and moving production delivery to Vercel.

This is a technical case study about the engineering decisions behind the migration. It is not a claim that every WordPress site should become headless, or that performance should be judged without real production measurement.

The decision

Why I did not just redesign WordPress

A WordPress redesign can be the right answer when the site is content-heavy, plugin needs are simple, and the team already has reliable hosting and maintenance. In this case, the public site needed a more controlled frontend than WordPress themes usually provide.

Keep editorial control

WordPress remained useful for pages, posts, projects, case studies, media, and structured content.

Reduce frontend weight

The public site no longer needed to inherit theme scripts, page-builder output, or plugin assets on every request.

Own the route structure

Next.js made it easier to define services, projects, locations, blog posts, metadata, schema, sitemap entries, and compatibility routes deliberately.

Improve deployment control

Vercel preview deployments, production env vars, analytics, and rollback made the frontend easier to ship and verify.

The practical architecture was simple: WordPress became the back office, Next.js became the storefront.

Design philosophy

The site needed to feel engineered, not decorated

Mackex is not a lifestyle brand or a SaaS startup. It is an electrical infrastructure contractor working across serious commercial, government, rail, road, mining, and energy environments. The design direction had to support that reality: practical, sturdy, easy to scan, and confident without becoming loud.

Lead with proof

The most persuasive design element was not animation. It was evidence: project categories, service depth, accreditations, client context, locations, and clear contact paths.

Make services understandable

Visitors should be able to quickly understand what Mackex does, where it operates, and which kind of infrastructure work fits their need.

Use motion carefully

A video hero can create presence, but the page still needs readable copy, stable layout, and fast access to services and contact options.

Design for mobile first decisions

Many visitors will arrive on a phone, often looking for capability, location, phone number, or credibility. The design had to make those answers immediate.

That philosophy shaped the frontend work. The site needed to look modern, but not fragile; polished, but not generic; fast, but still rich enough to communicate a real operating business.

Architecture

The production shape

Visitor
  |
  v
Vercel edge / Next.js App Router
  |
  +-- pre-rendered public routes
  +-- ISR refresh for content changes
  +-- image, metadata, sitemap, and schema control
  |
  v
WordPress content system
  |
  +-- WPGraphQL API
  +-- custom post types and media
  +-- editor-owned content

The frontend uses Next.js 15, React 19, TypeScript, Tailwind CSS, Apollo Client, and Vercel. The CMS side remains WordPress with WPGraphQL. The site includes a home page, about page, service pages, project and case-study pages, blog routes, NSW location pages, contact form handling, sitemap, robots, Open Graph metadata, and structured data.

The most important reliability detail is that the frontend has static fallbacks for important sections. If WordPress is slow or temporarily unavailable, the site should still be able to render a usable public experience instead of turning a CMS problem into a full-site outage.

Performance

Where the speed came from

I did not treat performance as one magic setting. The speed work came from removing runtime work, making content cacheable, and being more deliberate about what the browser downloads.

  1. Move public rendering out of WordPress. Next.js serves the public pages instead of asking PHP, a theme, and multiple plugins to assemble each visitor request.
  2. Pre-render content-heavy routes. Pages, services, projects, case studies, locations, and blog content can be generated ahead of time or refreshed through ISR instead of recomputed for every user.
  3. Use WPGraphQL as a content boundary. The frontend requests only the fields it needs instead of receiving full theme-rendered HTML for every concern.
  4. Optimize image delivery. Next.js image handling gives the frontend control over remote image dimensions, layout stability, lazy loading, and modern delivery patterns.
  5. Keep third-party scripts intentional. Analytics and Speed Insights are useful, but the site does not need a collection of WordPress plugin scripts on every public route.
  6. Build static fallbacks for critical content. A slow CMS should not make the core marketing site feel broken.

That combination is what makes the site feel fast: fewer moving parts on the public request path, less unnecessary JavaScript, predictable page generation, and a CDN-first deployment model.

SEO migration

The migration was also an SEO cleanup

A framework migration is risky if the new site loses URLs, metadata, schema, internal links, or crawl coverage. My pre-launch audit focused on the small technical details that can quietly hurt discoverability.

AreaWhat I checked or fixedWhy it mattered
SitemapIncluded service pages and the blog index, not only the obvious top-level routes.Search engines need the important commercial pages surfaced clearly.
Canonical URLsAdded canonical metadata on pages such as about, contact, and services.Canonical gaps can make simple pages look duplicative.
TitlesRemoved duplicated brand suffixes caused by page titles plus a layout title template.Search snippets should read like human titles, not template artifacts.
Open GraphAdded page URLs and corrected social-image behavior.LinkedIn and other platforms use these fields to deduplicate and preview shared pages.
NavigationMade service pages reachable from main navigation, not only footer or homepage cards.Important pages need internal links for both users and crawlers.
Phone linksUsed a proper international tel: format.Mobile users should be able to call without the link failing silently.
Server HTMLAvoided animated counters rendering as 0 in the initial HTML.No-JS users and crawlers should see the real business values.

The lesson is boring but important: a fast site that loses its commercial pages, metadata, or internal links is not a successful migration.

Thought process

The migration was not only a frontend rewrite

I approached the work as four connected problems: preserving the content that already existed, improving the public experience, protecting search visibility, and making future changes easier to ship.

Start with the content

Before thinking about components, I mapped the pages, services, projects, case studies, blog content, media, and business details that had to survive the move.

Separate editing from rendering

WordPress was still useful for managing content, but the visitor-facing site needed a more deliberate rendering layer, cleaner routes, and less frontend weight.

Treat SEO as migration work

Canonical URLs, titles, Open Graph fields, sitemap coverage, internal links, and server-rendered values were part of the launch, not polish to add later.

Plan for operations

The site needed revalidation, environment configuration, form delivery, analytics, fallback content, and post-launch measurement so the new stack would be maintainable.

That was the real shape of the project: content reconciliation, frontend performance, SEO repair, and operational cleanup all moving together.

What I would improve next

Headless WordPress still needs operational polish

Moving to Next.js solved the public frontend problem, but it also made the CMS contract more important. The next improvements are less flashy and more operational.

  • Use WordPress modified dates for sitemap lastModified values instead of stamping every URL with the deployment date.
  • Use on-demand revalidation from WordPress publish/update events so editors do not wait for the normal ISR window.
  • Keep GraphQL queries paginated so project growth does not silently truncate content.
  • Bring Yoast SEO fields into GraphQL where possible instead of duplicating authored SEO data in code.
  • Audit featured-image alt text in WordPress so accessibility and search metadata are content-owned, not code-guessed.
  • Move repeated hardcoded content, such as testimonials, FAQs, team content, and logos, into a cleaner CMS-controlled model when editing frequency justifies it.
Takeaways

My migration checklist

  1. Decide whether WordPress is the full site or only the CMS.
  2. Inventory routes, redirects, service pages, blog URLs, media URLs, metadata, and forms before building.
  3. Design the Next.js data layer around stable content contracts, not page-builder leftovers.
  4. Pre-render what can be pre-rendered, then add ISR or on-demand revalidation for content freshness.
  5. Keep a documented environment-variable, content-source, and launch-verification plan.
  6. Verify sitemap, robots, canonical URLs, Open Graph, schema, analytics, forms, and mobile links before launch.
  7. Measure production behavior after launch with real user data, not only local lab scores.

For Mackex, the win was not "WordPress bad, Next.js good." The win was putting each tool in the job it handles best: WordPress for content management, Next.js for the public experience, and Vercel for fast global delivery.

Related reading

Sources and next steps

Multi-Environment Cloud Architecture

How I separate environments and production boundaries when the hosting story gets more complex.

Secure CI/CD for Healthcare Apps

Deployment patterns that also apply to non-healthcare production sites.

Centralized Cloud Audit Logging

How to think about evidence and operational visibility after launch.

Plan a migration

If a WordPress site has outgrown its theme, start with routes, content, SEO risk, and launch ownership.

Public references checked while writing: Next.js App Router docs, Next.js ISR guide, Next.js Image component docs, WPGraphQL quick start, and Vercel Speed Insights docs.