Discuss your task

How to migrate your site from WordPress to Astro without losing SEO

Migrating a site from WordPress to Astro without losing SEO rests on three things: a full inventory of existing URLs and content before work starts, an exact map of 301 redirects from WordPress’s permalink structure to Astro’s file-based routing, and moving content into Content Collections with a type-safe schema instead of a relational database. Done carefully, the site holds its rankings by day 30 after launch and typically gets several times faster on Core Web Vitals, thanks to Astro’s zero-JavaScript-by-default architecture.

According to gautamkhorana.com, which reviewed migration practice in 2026, a typical move of a 30-100 page site from WordPress to Astro takes 6-10 weeks and usually costs 30-40% less than an equivalent Next.js project - mainly because Astro does not need trailing JavaScript infrastructure to serve static content.

In Exceltic.dev web development projects, we consistently see the same reason a team picks Astro over Next.js for a content site: on most WordPress sites, 80-90% of pages are static text with no interactivity, and Astro does not add a single extra kilobyte of JavaScript to them.

Below: what gets lost in a naive move, how Astro’s architecture fits a content site, the step-by-step migration process, and real Core Web Vitals ranges before and after.

The pain here is not felt by the developer, but by whoever owns organic traffic - a CMO or founder. A WordPress site with 15-20 active plugins is a standing risk: any plugin update can break the layout, and a week of downtime from an outdated plugin’s vulnerability means lost leads from search. The advice to “just keep plugins updated” does not scale to a team without a dedicated technical resource - which is exactly why companies look for an architecture with physically less of that risk.

Astro: a web framework for content sites that sends zero lines of JavaScript to the browser by default and adds interactivity only where it is explicitly needed - an approach called islands architecture.

Why companies leave WordPress for Astro

WordPress is a platform with server-side rendering on every request: the page is assembled through PHP and a MySQL database query, unless server-level caching is configured separately. As traffic or plugin count grows, server response time grows along with LCP.

Astro works differently: HTML is built once at build time (astro build), not on every user visit. For a site where 80-90% of pages are a blog, documentation, or marketing content, this removes the root cause of the slowdown instead of optimizing it after the fact.

The second reason is a better fit for the content model. WordPress was originally designed around posts and pages - text with metadata. Content Collections in Astro follow the same principle, but with a type-safe schema instead of arbitrary database fields: a frontmatter error is caught at build time instead of turning into an empty field in production.

The third reason is total cost of ownership. Managed WordPress hosting with acceptable performance (WP Engine, Kinsta) costs $30-300 a month depending on traffic, plus paid plugin licenses. A static Astro site on Vercel, Netlify, or Cloudflare Pages fits the free tier in most marketing site scenarios.

What gets lost when you migrate to Astro without a plan

A naive move means copying text over without a URL mapping and without a plan for functionality that ran through PHP hooks in WordPress. Three risk categories here are specific to moving to Astro, not generic to any migration.

Content model. WordPress stores everything in relational tables - wp_posts, wp_postmeta, taxonomies. When exporting to Markdown, you need to design a schema for each content type in advance: if you do not describe custom ACF (Advanced Custom Fields) fields explicitly in the collection schema, they get lost silently during conversion instead of throwing an error.

Static output by default. Contact forms, comments, live search, a related-posts block - in WordPress these run through PHP on every request. Astro serves pre-built HTML, so this functionality needs an explicit replacement: either a third-party service or an island component with explicit hydration.

Image optimization. WordPress automatically generates several sizes of every image on upload. In Astro, this is handled by the built-in <Image /> component and the astro:assets module, which optimizes images at build time - but old direct links to /wp-content/uploads/... need to be either preserved or explicitly redirected, or you lose traffic from Google Images.

We covered the more general list of risks in any migration - lost URLs, backlinks, meta tags - separately in the article SEO during site migration.

What to check before you start the move

A pre-move audit is an inventory of the current site’s content, SEO signals, and technical integrations, recorded before the first line of code on the new stack. Without it, the redirect map gets built from memory and is almost always incomplete.

For a move specifically to Astro, two additional items in this list matter: a full list of custom ACF fields for each entry type (they become the Content Collections schema) and a list of plugin PHP functionality that needs a replacement - a form, live search, comments, a calculator.

A detailed hour-by-hour checklist that applies to any move regardless of target stack is in the article website audit before migration.

How an Astro site’s architecture works

Islands architecture is Astro’s key architectural decision: every page renders to static HTML with no JavaScript by default, and interactive elements (a form, a carousel, a chat widget) are explicitly marked as islands and hydrated separately, without weighing down the rest of the page.

Instead of a database, content lives in Content Collections - a typed file structure validated by a Zod schema. A frontmatter error (a missing publish date, for example) is caught at astro build time instead of surfacing as an empty field in production:

Example post collection schema
import { defineCollection, z } from 'astro:content';

const blog = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    publishedAt: z.date(),
    seoTitle: z.string().max(60),
    seoDescription: z.string().max(155),
    heroImage: z.string().optional(),
  }),
});

export const collections = { blog };

Fetching data from a collection to generate pages goes through getCollection() - a function that returns a list of entries and can optionally filter them by schema fields.

For sites where some pages need full client-side logic - a customer account area, complex catalog filters - Next.js with its React Server Components remains the better choice; we covered the difference between these two architectures for a marketing site in the article migrating from WordPress to Next.js. But for a site where content is 80-90% of pages, Astro delivers the same result with less code and no client-side JavaScript tail.

The step-by-step process for migrating from WordPress to Astro

Below is the sequence that, in practice, minimizes the risk of losing traffic when the steps are followed in order.

Step 1. Export content from WordPress

Export content through the built-in exporter (Tools > Export in the WordPress admin, a WXR file) or through the REST API (/wp-json/wp/v2/posts) if you need finer control over fields and export pagination.

Step 2. Convert to Markdown and define the schema

The wordpress-export-to-markdown tool reads the WXR file and generates Markdown files with frontmatter, downloading images along the way. WordPress shortcodes are not converted automatically - the exporter outputs them as plain text, and you need to manually replace them with Markdown syntax or Astro components.

Step 3. Build the redirect map

Map WordPress’s permalink structure (/category/post-slug/ or /post-slug/ depending on permalink settings) to Astro’s new file-based routing. Redirects are defined directly in the config:

Example redirects in astro.config.mjs
export default defineConfig({
  redirects: {
    '/category/wordpress-tips/[slug]': '/blog/[slug]',
    '/wp-content/uploads/[...path]': '/media/[...path]',
  },
});

Astro serves these redirects with a 301 status code for GET requests. There is a known caveat: the built-in redirects config does not always handle trailing-slash and no-trailing-slash URL variants correctly - the redirect map should explicitly list both variants, and the resulting behavior should be checked on staging before launch.

Step 4. Migrate the media library

Images from /wp-content/uploads/ are either copied into public/ with the original paths preserved, or uploaded to a CDN. Either way, images on content pages should be explicitly switched to the <Image /> component from astro:assets, to get automatic srcset generation and modern formats (WebP, AVIF) at build time instead of relying on plugins like Smush.

Step 5. Rebuild plugin functionality

Contact forms (Contact Form 7, Gravity Forms) are replaced with an island component that submits through a third-party form service or your own API endpoint. Comments move to an embeddable service (Giscus, Disqus) or get dropped if their volume was low. The related-posts block gets rebuilt with logic based on collection tags through getCollection(), rather than migrated by hand.

Step 6. Test on staging and launch

Crawl the staging version with Screaming Frog, cross-check it against the original URL list from the audit, and confirm that no page from Search Console’s top-performing list returns a 404. After switching DNS, submit the new sitemap.xml to Google Search Console and manually request reindexing for the highest-traffic pages.

Core Web Vitals before and after the move to Astro

Core Web Vitals: Google metrics that measure a page’s real-world speed and stability for the user - LCP (main content load), CLS (visual stability), and INP (interaction responsiveness). The “good” thresholds per web.dev: LCP under 2.5 seconds, CLS under 0.1, INP under 200 ms.

In a typical project moving a 100-300 page content site from WordPress on shared hosting to Astro deployed on static hosting, the numbers shift within these ranges.

  • LCP: from 3.5-5.5 seconds to 0.8-1.8 seconds - because the database query on every render disappears entirely: the page is already built as HTML at build time.
  • CLS: from 0.15-0.3 to 0.01-0.06 - because of explicit image dimensions through <Image /> instead of dynamically loaded ad and widget blocks.
  • INP: from 300-500 ms to 50-150 ms - because of the architectural absence of client-side JavaScript where the page is not interactive: only explicitly marked islands get hydrated, not the whole document.

Developer Kashif Aziz, writing about his own blog migration, describes the result as a perfect 100 Lighthouse score after moving to Astro - a telling, though not universal, example of the upper end of the range for a simple blog with no third-party tracking. Mobile PageSpeed Insights scores in typical projects climb from 35-55 to 90-99; the exact number depends on how much third-party JavaScript (analytics, chat widgets, pixels) migrates along with the site.

Common mistakes when migrating to Astro

Forgetting that shortcodes do not convert. Markdown exporters output WordPress shortcodes ([gallery], [contact-form-7]) as plain text in square brackets - without a manual replacement, they stay as clutter on the page.

Not accounting for the trailing slash in redirects. Astro’s built-in redirects mechanism has historically handled trailing-slash URL mismatches poorly - if WordPress served /post-slug/ and the new route is set up without the slash, some visits can fail to redirect without an explicit check.

Migrating images without preserving paths. If old direct links to /wp-content/uploads/2024/03/ do not redirect to the new location, you lose traffic from Google Images and break external links to the images from other sites.

Not designing the collection schema up front. Content Collections validate frontmatter against a Zod schema - if the schema is written after the fact, fitted to already-converted files, it is easy to miss a field that was an important custom attribute in WordPress.

Leaving auto-generated SEO tags unchecked. Title, description, canonical, and Open Graph, which Yoast or Rank Math assembled in WordPress, need to be explicitly set in each collection in Astro - otherwise pages go to production with default or empty meta tags.

Who the migration to Astro is right for

Moving to Astro makes sense for a marketing or content site where the vast majority of pages are text: a blog, documentation, case studies, landing pages with no complex client-side logic. Companies with 15-20+ employees, where WordPress is already hitting a performance or maintenance-cost ceiling and the team is ready to manage content through Markdown files in a repository instead of a visual editor, get the most out of this architecture.

It is a worse fit for a scenario where the site needs complex interactive sections - a customer account area, multi-step stateful forms, a catalog with dozens of filters. Astro can implement this kind of logic through islands too, but the amount of custom code involved starts to converge with Next.js, and the choice more often shifts that way.

Frequently asked questions

How long does migrating from WordPress to Astro take?

For a 50-100 page site with a typical content mix, migration usually takes 4-8 weeks, including audit, development, testing, and watching indexing after launch. Sites with non-standard plugin functionality - calculators, complex filters, customer account areas - need more time to recreate that logic as island components, not to move the text itself.

What happens to Google rankings right after the move?

With a correct redirect map and preserved technical signals, the short-term dip is usually minimal - Google processes 301 redirects over a few days to a few weeks. A more noticeable and longer drop happens when some URLs are left without a redirect, or when the trailing slash in the new routes does not match the old permalink structure.

Can WordPress stay as the content source while Astro handles only the front end?

Yes, this is a working headless setup: WordPress stays the familiar panel for editors, and Astro pulls content through the REST API or WPGraphQL at build time. This path removes some of the content-conversion risk, but it does not remove the dependency on PHP infrastructure and the vulnerabilities that come with it.

Astro or Next.js - which one for a move off WordPress?

If 80-90% of the site is static content with no complex interactivity, Astro usually gets you there faster with less code, thanks to islands architecture. Next.js makes more sense if the site has significant client-side logic - a customer account area, dynamic dashboards, authentication. We covered a detailed comparison of the two architectures in the article on migrating from WordPress to Next.js.

How do you migrate forms and comments to a static Astro site?

A form is implemented as an island component that submits data to a third-party form service or your own serverless endpoint - the form itself stays interactive, but the page around it is static. Comments are usually moved to an embeddable service like Giscus, which stores data in an external system and loads as a separate island component, with no server-side component needed on the Astro side.

What to do next

  • Audit the current site: a full URL list, custom ACF fields, and plugin PHP functionality that needs replacing.
  • Design the Content Collections schema before converting content, not after - this protects against silently losing custom fields.
  • Build the redirect map accounting for the trailing slash, and test it on staging before switching DNS.
  • Replace static plugin functionality (forms, comments, related posts) with island components or third-party services ahead of time, not at the last moment before launch.

If you are evaluating a move from WordPress to Astro right now, tell the Exceltic.dev team the size of your site and the key plugin functionality it runs on. We will map the migration risks specific to Astro and give you an honest timeline estimate.

More articles

All →