
Leaving WordPress without losing 15 years of URLs
Exporting a WordPress site is the easy part. The REST API hands over every post as JSON in an afternoon, and that afternoon is maybe five percent of the job. The expensive part is the URL map that fifteen years of readers and search crawlers already memorised, plus the behaviour living inside your plugins.
The content comes out in an afternoon
A GET to /wp/v2/posts returns the whole post record: title, content, excerpt, slug, link, guid, modified, categories and tags. It is clean, documented JSON, and for a blog with a few thousand posts you can have the lot on disk before lunch. One thing catches people. The per_page argument defaults to 10, so a quick script that forgets to paginate walks away with the first page and reports success. Count the rows against the WordPress admin before you trust the export.
Comments live somewhere else. They sit at /wp/v2/comments as their own collection, and the fields that identify a commenter behave differently from the rest: author_email, author_ip and author_user_agent only appear in the edit context. An unauthenticated crawl gives you the visible comment text and silently drops the person behind it. If you want the same readers to keep their identity on the new site, authenticate the export before you run it, not after.
The redirect map is the actual migration
Every post carries both a slug and a full link, and those two disagree more than you expect once a site has changed permalink structure a couple of times. A URL like /2011/03/a-post-from-2011/ has to land on whatever you call it now, and it has to land there with a 301. Astro has shipped a redirects config since 2.9.0 that maps an old route to a new one, and for GET requests it issues a 301 permanent redirect, 308 for everything else. Generate that map from the export you already have. Typing it by hand is how you lose the long tail.
Then decide on trailing slashes and do it once. Astro trailingSlash takes always, never or ignore, and it decides whether /about and /about/ are the same route. WordPress served trailing slashes by default for years, so picking never means handing every crawler an extra redirect hop on every historical URL. Worth noting that Astro says trailing slashes on prerendered pages are handled by the hosting platform and may not respect the config, so check the behaviour on your actual host rather than in dev.
We did this for Stay World Class, moving Webflow and Xano onto Next.js, NestJS and Supabase. The migration ran as a four stage ETL that mapped every legacy ID onto a PostgreSQL UUID instead of renumbering. That mapping is boring until the day someone finds a dead link from 2014 and you can still answer what it used to point at. Lighthouse went from 55.91 to 91 out of 100 and LCP came down 77 percent, but the ID map is the part I would keep if I could only keep one thing.
Your plugins were the application
Plugins hold behaviour, and behaviour is not in /wp/v2/posts. The contact form that routes to two inboxes and the structured data your rich snippets depend on do not come out with the content. Write the inventory while the site is still running and you can still open wp-admin. Once the DNS moves, your only record of what the site did is what you wrote down.
Pay special attention to any redirect plugin. Most sites that have already moved once are carrying a redirect table inside one, and that table is often the only surviving record of URLs that died in an earlier migration. Lose it and you quietly break links nobody has thought about for a decade. Export it first, before the themes, before the media.
When staying put is the right answer
WordPress is cheap and it works. WordPress.com Personal is 9 dollars a month billed monthly, or 4 dollars a month if you pay yearly, with 6 GB of storage; Premium is 18 dollars monthly or 8 dollars a month yearly with 13 GB. WP Engine starts its Managed Hosting Platform at 28 dollars a month. Against a rebuild, a few hundred dollars a year is nothing. If your site is articles plus a contact form, your traffic is nowhere near a tier limit and nobody on your team is fighting the CMS, there is no argument here. Keep publishing.
The case for moving starts when you want the site to do something WordPress makes you fight for: a product behind a login, or a performance budget the plugin stack cannot hit. That is a different kind of problem from publishing, and it is the point where the plugin ecosystem stops saving you time and starts spending it. Until you hit that, a blog that loads fine and earns its keep should stay a blog that loads fine.
