Move a WordPress site to Astro without losing rankings

Rankings follow URLs, not the CMS. The redirect map, trailing slash, metadata, forms and comments when a WordPress site becomes an Astro site.

Published 8 minute readWebsites
A page moving along an arrow onto a new page, with nothing dropped on the way

When we rebuilt appbuff.net in Astro this year, the first file we wrote was not a page. It was public/_redirects, 34 lines long, one line for every URL the old site had used since 2021. The old site was Angular, not WordPress, but the risk was the same one every WordPress owner asks about: years of search traffic attached to addresses that were about to stop existing.

Google doesn’t rank a CMS. It ranks URLs. Its site move guide asks for one thing above everything else: map every old URL to a new one and send a permanent redirect. Do that, and converting WordPress to Astro is a rebuild of the parts people see, with the parts Google sees kept intact.

TLDR

A WordPress to Astro migration keeps its rankings when every old URL either stays the same or 301-redirects to its closest new page. Build the URL list from the WordPress sitemap and Search Console first, match the old trailing slash, carry titles, descriptions and schema into the new pages, and plan forms and comments before launch. Expect a few weeks of movement in Search Console, then check the old URL list for anything that returns 404.

Rankings follow URLs

Google’s guide is short on this. Use server-side permanent redirects, 301 or 308, because they “don’t cause a loss in PageRank”. Keep them “generally at least 1 year”. Redirect straight to the final page, with no chains. And expect “temporary fluctuation in site ranking during the move”, for a few weeks or more on a medium-sized site.

If the domain stays the same, there is no Change of Address step in Search Console. Google says that tool is only for moving from one domain or subdomain to another. A WordPress to Astro move on the same domain is, to Google, a site that changed some paths and kept the rest.

So the work is a list. Everything below is about making that list complete.

Build the URL list before you build pages

A WordPress site has more public URLs than its owner thinks. Pages and posts are the obvious ones. Category archives, tag archives, author pages, paginated archives like /blog/page/2/, attachment pages and the RSS feed at /feed/ are all URLs too, and some of them hold rankings.

Three sources, merged into one spreadsheet:

  1. The WordPress sitemap. Since WordPress 5.5, core publishes one at /wp-sitemap.xml, covering public post types, taxonomies and author archives. Yoast, Rank Math and similar plugins replace it with their own, usually at /sitemap_index.xml.
  2. Search Console, Performance report, Pages tab, for the last 16 months. Any URL with impressions goes on the list, whatever the sitemap says.
  3. Your analytics, for URLs that get visits from links on other sites.

Each row gets an old URL, a new URL, and a decision: same path, redirect, or gone. Keep the same path wherever you can. A redirect costs a hop; an unchanged URL costs nothing.

Match the old trailing slash

This is the step that quietly breaks migrations. WordPress pretty permalinks end with a slash: example.com/my-post/. The WordPress permalink docs show the default structures that way. If the new site serves example.com/my-post instead, every URL on the site becomes a redirect, or worse, a duplicate.

Astro decides this with two settings. build.format controls the files it writes, and trailingSlash controls which form of the URL it accepts. The Astro configuration reference says to pair them: directory with 'always', file with 'never'. For a site coming from WordPress, the first pair keeps every old URL exactly as it was.

// astro.config.mjs
export default defineConfig({
  site: 'https://example.com',
  trailingSlash: 'always',
  build: { format: 'directory' },
});

The same reference warns that for prerendered pages the slash is “handled by the hosting platform”, so check the live behavior on your host after the first deploy, not only on your laptop. Appbuff runs the other pair, file and 'never', because the old Angular site had no slashes. Same rule, opposite answer.

Write the redirect map

Every row that changed becomes a redirect. On Netlify that’s a plain text file named _redirects in the published folder. One rule per line: old path, new path, status. The Netlify redirect options say the status is 301 when you leave it out, and the first matching rule wins, so specific lines go above general ones.

# Renamed pages
/about-us/                 /about/                      301
/services/web-design/      /services/websites/          301

# Date-based WordPress posts to flat Astro slugs
/2023/04/12/spring-menu/   /blog/spring-menu/           301

# Tag archives that never ranked go to the blog
/tag/*                     /blog/                       301

The splat line at the bottom is the safety net. An asterisk matches anything after it, so every tag page lands somewhere useful even if one was missed in the list. Use splats for archive families, never as a replacement for the list itself.

Appbuff’s own map follows the same shape. Service pages from 2021 point at their 2026 equivalents, old blog posts point at the blog, and two catch-all lines handle the /blog/* and /legal/* prefixes the old site used.

Carry the metadata over

A page that keeps its URL but loses its title tag has still changed in Google’s eyes. Before the old site goes away, export for every page: the SEO title, the meta description, the canonical URL, the social image, and the structured data.

If the site runs Yoast SEO, this is one request per page. Yoast adds a yoast_head_json field to the WordPress REST API with the title, description, canonical, Open Graph tags and the schema graph, as its REST API docs show. Those values go into each page’s front matter in Astro, and the layout writes them back into the head.

Keep the titles you have unless you know they’re wrong. A migration is a bad week to rewrite fifty titles at once, because when rankings move you won’t know whether the move or the copy caused it.

Content and images

WordPress exports content from Tools, then Export. The export docs list what the WXR file holds: posts, pages, custom post types, comments, custom fields, categories, tags and users. It holds no image files, only references to them.

The tool the Astro migration guide points to, wordpress-export-to-markdown, turns that file into one Markdown file per post with front matter, and downloads the images while it runs. The old site has to stay online for the download.

Put the images in src/, not public/. The Astro images guide says images in src/ get converted to WebP or AVIF and given width and height attributes, which stops layout shift. Images in public/ are “never optimized”.

Plain posts convert cleanly. Pages made in a page builder don’t. Their content is buried in builder markup and shortcodes, and the honest fix is to rebuild those pages as Astro components, using the old page as the reference. On most small business sites that’s the home page, the services pages and the contact page: the pages that matter most, so the rebuild is worth it.

Forms and comments

A static site has no PHP, so Contact Form 7 and Gravity Forms go with WordPress. Two replacements cover most sites. A host-level form handler, like Netlify Forms, picks up a plain HTML form with a data-netlify="true" attribute at deploy time, as the Netlify Forms docs explain. Or a single server function sends the email. Appbuff uses the second: one on-demand route handles the contact form with a honeypot, a rate limit and an email through Resend, and every other page is static HTML.

Comments need a decision, not a tool. The export file already holds every approved comment, so old discussions can stay on each post as static text. For new comments, giscus runs on GitHub Discussions with no ads and no tracking. Many small business blogs drop comments at this point, and very few readers notice.

When to keep WordPress as the editor

Some teams write in WordPress every day and don’t want to change that. They don’t have to. The Astro WordPress guide uses WordPress as a headless CMS: posts stay in the dashboard, and Astro reads them from /wp-json/wp/v2/ at build time.

The trade is real. WordPress still needs hosting and updates, and a static Astro site needs a rebuild each time someone publishes. What changes is exposure: the public site is static files, and the WordPress install can sit on a separate address that visitors never load. For a team that posts weekly and has no developer, a Git-based editor like Keystatic is often the simpler answer, with content stored as files and no database at all. The Astro vs WordPress comparison covers who should keep which.

The week after launch

Submit the new sitemap in Search Console and remove the old one. Then test every old URL from the spreadsheet against the live site. A short shell loop does it:

while read url; do
  code=$(curl -s -o /dev/null -w "%{http_code}" "$url")
  echo "$code $url"
done < old-urls.txt | grep -v "^200\|^301"

Anything it prints is a URL that returns neither the page nor a redirect. Fix those first. Then watch the Search Console Pages report for two or three weeks. Old URLs moving into “Page with redirect” is the move working as planned.

If you’d rather hand the whole list to someone else, our Astro website service starts at $1,500 fixed and the redirect map is written before the first page is built. Hosting the finished site can cost nothing, and the free hosting guide shows where.

Questions

Will a WordPress to Astro migration hurt my Google rankings?

Expect a few weeks of movement while Google swaps old URLs for new ones. Google's own site move guide says so. Rankings drop for good when old URLs return 404, when titles and descriptions get lost, or when internal links point at redirects. A complete URL map with 301 redirects avoids all three.

Can I keep writing posts in WordPress after moving to Astro?

Yes. WordPress can stay as a headless CMS: you write in the same dashboard, and Astro pulls the posts from the REST API at /wp-json/wp/v2/. You still host and update WordPress, and a static Astro site needs a rebuild each time you publish.

What happens to my WordPress plugins?

They stop running, because Astro does not run PHP. Each plugin becomes one of three things: a feature built into the Astro site, a hosted service such as a form handler, or nothing, because a static site doesn't need it. Caching, security and most SEO plugins fall in the last group.

Have this problem on your store?Two sentences about it get you a written quote, or a plugin or app recommendation, within 48 hours.
Get a fixed quote