Get off the plugin treadmill without losing your content or your rankings.
We migrate WordPress sites to Astro, Next.js, or headless WP architectures — preserving every URL, redirect, schema, and Yoast field. Editors keep their workflow. Pages load in under a second.
Your WordPress site is one plugin update away from a Monday morning incident.
It started clean. Then came Yoast, WPBakery, Elementor, WooCommerce, a membership plugin, three caching layers, a security plugin that fights the caching layer, and a backup plugin that occasionally bricks the database. TTFB is 2 seconds on a good day. The admin is unusable on a slow connection. Every PHP minor version forces a regression test. Marketing wants a landing page; engineering wants to delete the whole thing. Meanwhile, Core Web Vitals are tanking your organic traffic and the host bill keeps climbing.
- ▸ Page Speed scores under 40 on mobile, with LCP routinely above 4 seconds even on cached pages.
- ▸ 30-60 active plugins, half of which haven't been updated in 18 months and silently conflict on minor releases.
- ▸ Editorial team blocked because preview, staging, and production drift constantly thanks to plugin state in the database.
- ▸ No clean separation between content, presentation, and behavior — every redesign turns into a six-month rebuild.
Migrate the content model first, the rendering layer second.
- STEP-01
Audit plugins and content shape
We crawl the site, dump the database, and inventory every active plugin, custom post type, ACF field, shortcode, and Gutenberg block. Most WordPress sites have 30-60 plugins where 5 actually matter. We mark what ships, what dies, and what becomes a build-time function.
- STEP-02
Lock the content model
Before touching the frontend, we define the canonical content schema in TypeScript or Zod. Posts, pages, authors, taxonomies, media, and custom fields get typed contracts. WordPress either stays as the headless source via WPGraphQL/REST, or content gets exported to MDX/Markdown in a Git repo.
- STEP-03
Rebuild rendering in Astro or Next.js
Astro for content-heavy marketing sites that should be 95% static. Next.js when you need ISR, auth, or app-like interactivity. We port templates 1:1 first, then refactor. Shortcodes become components. Page builder output gets normalized into clean HTML.
- STEP-04
Preserve SEO and redirects
Every existing URL gets mapped. We diff the old sitemap against the new build, generate 301s for any path changes, and carry over canonical tags, meta descriptions, OG images, and structured data. Yoast/RankMath fields are extracted from postmeta and rendered into the new <head>.
- STEP-05
Cut over with parallel monitoring
We deploy to a staging domain, run Lighthouse and Screaming Frog against both old and new, then flip DNS. Search Console gets the new sitemap the same day. We monitor crawl errors and rankings for 30 days and fix any redirect gaps in week one.
// astro.config.mjs - fetching WordPress as a headless source at build time
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
export default defineConfig({
site: 'https://example.com',
output: 'static',
integrations: [sitemap()],
});
// src/lib/wp.ts
import { z } from 'zod';
const Post = z.object({
id: z.number(),
slug: z.string(),
title: z.object({ rendered: z.string() }),
content: z.object({ rendered: z.string() }),
yoast_head_json: z.object({
title: z.string().optional(),
description: z.string().optional(),
canonical: z.string().optional(),
og_image: z.array(z.object({ url: z.string() })).optional(),
}).optional(),
modified: z.string(),
});
export async function getAllPosts() {
const posts: unknown[] = [];
let page = 1;
while (true) {
const res = await fetch(
`${import.meta.env.WP_URL}/wp-json/wp/v2/posts?per_page=100&page=${page}`
);
if (res.status === 400) break; // past last page
posts.push(...(await res.json()));
page++;
}
return z.array(Post).parse(posts);
} Validating WordPress REST responses with Zod at build time catches schema drift before it ships broken pages to production.
Field FAQ.
→ Should we keep WordPress as a headless CMS or replace it entirely?
Depends on who edits content. If non-technical marketers publish daily and rely on the WP admin, keep it as a headless source via WPGraphQL or the REST API and rebuild only the frontend. If content changes monthly and developers own it, export to Markdown/MDX in Git and kill WordPress entirely. The middle path — headless WP — preserves editorial workflow but still means patching PHP and MySQL forever.
→ What happens to our SEO during the migration?
If done right, nothing bad. We extract every Yoast or RankMath field from postmeta, preserve canonical URLs, render identical structured data (Article, BreadcrumbList, Organization), and submit a fresh sitemap on cutover. Any URL that changes gets a 301. We typically see Core Web Vitals improve dramatically — LCP often drops from 4-6s to under 1s — which Google rewards within weeks. Rankings usually hold or improve.
→ How do you handle Gutenberg blocks and page builders like Elementor or Divi?
Gutenberg blocks are tractable because they output semantic HTML with parseable comments. We render them through a block-to-component mapper. Elementor and Divi are harder — they emit nested div soup with inline styles. For those we usually render the final HTML as-is for legacy pages and rebuild key templates as native Astro/Next components. Page builder lock-in is one of the main reasons clients call us.
→ How long does a typical WordPress-to-headless migration take?
For a content site under 500 pages with standard post types, 4-8 weeks end to end. Larger sites with custom plugins, WooCommerce, membership logic, or 10k+ posts run 10-16 weeks. The variable is rarely page count — it's how much custom PHP needs to be replaced and how messy the content model is. We give a fixed scope after the audit, not before.
→ What about WooCommerce? Can it go headless too?
Yes, but think carefully. WooCommerce has a REST API and the Store API, and projects like Next.js Commerce can front it. That said, if you're already migrating, this is the moment to evaluate Shopify, Medusa, or a purpose-built commerce backend. WooCommerce's plugin ecosystem is its strength and its weakness — you inherit the same bloat problem you're trying to escape. We help clients decide based on order volume and SKU complexity.
→ Do editors lose features when we go headless?
Some, yes. Live preview gets more complicated — it requires a preview route in Next.js or a staging build pipeline. Plugins that inject frontend behavior (popups, A/B tests, related posts widgets) need to be rebuilt as components or replaced with dedicated tools. The block editor still works for content. We document every workflow change before cutover so the editorial team isn't surprised on day one.
→ Why Astro vs Next.js vs Gatsby for the new frontend?
Astro for content sites that are 90%+ static — marketing pages, blogs, documentation. It ships almost no JavaScript by default and builds fast. Next.js when you need ISR, server actions, authentication, or heavy interactivity. Gatsby we generally avoid on new projects; the build times and plugin ecosystem haven't aged well. We make the call based on traffic patterns, content update frequency, and what your team can maintain.
→ Is this work eligible for federal SDVOSB set-aside contracts?
Yes. VooStack is SDVOSB-certified through SBA's VetCert, and application modernization including CMS migrations falls under common NAICS codes we hold (541511, 541512). Federal agencies running aging WordPress or Drupal sites can contract this work directly under SDVOSB set-asides, sole-source up to the threshold, or through GSA vehicles. We've shipped modernization work for federal clients and can provide capability statements on request.
→ What hosting do you recommend after the migration?
For static Astro output: Cloudflare Pages, Netlify, or Vercel — pick based on your edge needs and team familiarity. For Next.js with ISR: Vercel is the path of least resistance, though we deploy to AWS (Amplify, ECS, or self-hosted on Fargate) when clients need VPC isolation or have FedRAMP requirements. Headless WordPress itself we usually keep on a managed host like Kinsta or WP Engine, locked behind a firewall since it's no longer public-facing.
Continue recon.
Modernization services
Legacy app and CMS modernization, cloud migration, and platform replatforming engagements.
REL-02Migration case studies
How we've replatformed content sites, intranets, and federal portals off legacy stacks.
REL-03Fixed-scope packages
Audit, migration, and post-launch support packages with defined timelines and deliverables.
REL-04Scope a migration
Send us your URL and current stack — we'll return a written assessment in 5 business days.
Ready to get off the WordPress treadmill? Let's scope the migration.
Talk to a VooStack operator. We respond within one business day.