---
title: "Site Migration SEO for Vue Apps"
description: "Redirect maps, canonical fixes, and realistic recovery timelines for domain moves, URL restructures, and platform migrations that don't tank rankings."
canonical_url: "https://nuxtseo.com/learn-seo/vue/launch-and-listen/site-migration"
last_updated: "2026-07-16"
---

<key-takeaways>

- Map every old URL to exactly one new URL and redirect it server-side with a real 301. Client-side JavaScript redirects don't pass ranking signals.
- Recovery is slow: across 1,052 tracked migrations only 23% of sites recovered traffic within 90 days, and the median took 304 days, so don't panic at the 60-day mark.
- File the Change of Address tool in Search Console for domain changes; it forwards ranking signals for 180 days, well short of the year or more you should keep the actual redirects live.
- Search Console's Generative AI performance report can show AI Overview impressions by page, so you can compare old and new URLs after launch, though it's impressions-only and still rolling out to a subset of sites.

</key-takeaways>

Site migrations lose search rankings when done wrong. Recovery is usually much slower than blog posts promise: across 1,052 tracked domain migrations, [SALT.agency found](https://salt.agency/blog/27-of-domain-migrations-recover-in-90-days/) only 23% of sites recovered traffic within 90 days, with a median recovery time of 304 days. Poor migrations that skip redirect mapping or leave canonicals pointed at old URLs can take far longer, or never fully recover.

The difference is planning, correct redirects, and post-migration monitoring.

## Types of Migrations

Each migration type affects SEO differently:

![Migration Decision Tree](/images/learn-seo/vue/migration-decision-tree.svg)

**Domain change** (old.com → new.com): file the [Change of Address tool](https://support.google.com/webmasters/answer/9370220) in Search Console for every subdomain variant (www, non-www, and any others you use); it forwards ranking signals for 180 days, but keep the redirects themselves live much longer.

**Protocol change** (HTTP → HTTPS): update every canonical tag to the HTTPS version. Leaving canonicals pointed at HTTP while redirects send Google to HTTPS creates a loop.

**URL structure change** (`/blog/post` → `/posts/post`): the type most prone to redirect chains. Map every old URL to exactly one new URL, with no intermediate hops.

**Platform/framework change**: moving from WordPress to Vue, or Vue to Nuxt, usually changes URL structure too. Build a full redirect map rather than assuming paths carry over.

**Site redesign with the same URLs**: the lowest-risk migration since nothing needs to redirect, but still validate canonical tags and internal links against the new templates.

## Pre-Migration Checklist

Start here before touching production:

1. **Crawl the old site completely.** Use [Screaming Frog](https://screamingfrog.co.uk) or similar to export every URL; you need a full inventory.
2. **Export indexed URLs and AI Search data from Search Console.** Pull the Page Indexing report and Performance data, including the AI Search Appearance filter, for your baseline.
3. **Document current rankings.** Export Search Console Performance for your top pages so you have something to compare against after launch.
4. **Build a redirect mapping spreadsheet.** Three columns: Old URL, New URL, target status code (200, 301, 410). Map every URL, no exceptions.

For sites with 10,000+ pages, [Google suggests migrating in sections](https://developers.google.com/search/docs/crawling-indexing/site-move-with-url-changes) and testing with a small section before moving the rest, though it notes a section move isn't fully representative of how a whole-site move behaves in Search.

## Redirect Mapping Strategy

Mapping is where migrations succeed or fail.

**1:1 mapping** (preferred): each old URL redirects to exactly one new URL with identical or similar content.

```text
/blog/vue-seo-guide → /guides/vue-seo
/products/item-123 → /products/item-123 (unchanged)
```

**Pattern-based redirects**: for systematic URL changes, use regex or route patterns to redirect an entire section at once.

```text
/blog/:slug → /articles/:slug
/category/:cat/page/:num → /c/:cat?page=:num
```

**Deleted pages**: don't 404 a page that had traffic or backlinks. Redirect it to the closest relevant alternative. If nothing fits, return 410 (Gone) rather than 404 to signal the removal is permanent.

## Implementing Redirects in Vue

SEO requires server-side redirects. Client-side redirects (JavaScript) don't pass ranking signals and Google may not follow them at all.

### Express Server

```ts
import express from 'express'

const app = express()

// Single redirect
app.get('/old-url', (req, res) => {
  res.redirect(301, '/new-url')
})

// Pattern redirect
app.get('/blog/:slug', (req, res) => {
  res.redirect(301, `/posts/${req.params.slug}`)
})

// Redirect map for bulk redirects
const redirects = {
  '/old-page-1': '/new-page-1',
  '/old-page-2': '/new-page-2',
  '/company/about': '/about'
}

app.use((req, res, next) => {
  const redirect = redirects[req.path]
  if (redirect) {
    return res.redirect(301, redirect)
  }
  next()
})
```

### Vite Server

```ts
// vite.config.ts
import { defineConfig } from 'vite'

export default defineConfig({
  server: {
    middleware: [
      (req, res, next) => {
        const redirects = {
          '/old-path': '/new-path',
          '/blog': '/posts'
        }

        const redirect = redirects[req.url]
        if (redirect) {
          res.writeHead(301, { Location: redirect })
          res.end()
          return
        }
        next()
      }
    ]
  }
})
```

### H3 Server (Nitro/Nuxt)

```ts
// server/middleware/redirects.ts
import { defineEventHandler, sendRedirect } from 'h3'

const redirects = {
  '/old-url': '/new-url',
  '/blog': '/posts'
}

export default defineEventHandler((event) => {
  const redirect = redirects[event.path]
  if (redirect) {
    return sendRedirect(event, redirect, 301)
  }
})
```

For large redirect maps (1000+ URLs), load from JSON file:

```ts
import redirectData from './redirects.json'

export default defineEventHandler((event) => {
  const redirect = redirectData[event.path]
  if (redirect) {
    return sendRedirect(event, redirect, 301)
  }
})
```

## Avoid Redirect Chains

A chain forms when URL A redirects to B, which redirects to C, most often because a new migration redirect gets layered on top of an old one. Each extra hop dilutes ranking signal and slows crawling.

Common scenario: you have an old redirect (A → B) and add a new migration redirect (B → C), and now you have a chain: A → B → C.

Fix: point every redirect directly at the final destination, consolidating old and new redirects into single-hop redirects.

```ts
// Bad: creates a chain
// Old redirect: /page-v1 → /page-v2
// New redirect: /page-v2 → /page-v3
// Result: /page-v1 → /page-v2 → /page-v3

// Good: consolidate
const redirects = {
  '/page-v1': '/page-v3', // direct to final
  '/page-v2': '/page-v3'
}
```

Test redirects before launch: each should return 301 and resolve to a 200 in one hop.

## Update Canonical Tags

When URLs change, canonical tags must point at the new URLs. A [canonical tag pointing at a redirected URL](https://developers.google.com/search/docs/crawling-indexing/canonicalization) creates a loop, and it's a common migration mistake.

```html
<!-- Bad: canonical points to old URL -->
<link rel="canonical" href="https://example.com/old-url">

<!-- Good: canonical points to new URL -->
<link rel="canonical" href="https://example.com/new-url">
```

In Vue with Unhead:

```ts
import { useHead } from '@unhead/vue'

useHead({
  link: [
    { rel: 'canonical', href: 'https://example.com/new-url' }
  ]
})
```

Scan the staging site before launch to confirm every canonical points at a new URL, not an old one.

## Post-Migration Steps

The hours after migration are when problems surface.

1. **Update the Search Console property.** For domain changes, file the [Change of Address tool](https://support.google.com/webmasters/answer/9370220); it forwards ranking signals for 180 days.
2. **Submit the new sitemap.** Generate it with the new URLs, submit in Search Console, and remove the old one from `robots.txt`.
3. **Request indexing of key pages.** In Search Console, request indexing for your homepage and top 10-20 pages to speed up discovery.
4. **Check the Page Indexing report daily.** Watch for 404s, soft 404s, redirect errors, and pages Google isn't following, for at least the first two weeks.
5. **Watch server capacity.** [Google crawls new sites more heavily right after a migration](https://developers.google.com/search/docs/crawling-indexing/site-move-with-url-changes) since every redirected old-URL crawl adds to normal crawling of the new site.
6. **Compare organic traffic before and after.** Set up a date comparison in your analytics tool and track organic sessions specifically, separate from other channels.
7. **Monitor AI Overview impressions by page** with Search Console's Generative AI performance report, which launched in June 2026. It's impressions-only, filtered by page, country, device, and date, and still rolling out to a subset of sites, so treat it as a directional signal rather than a full picture.

<tip title="Don't forget AI bots">

Make sure your redirects also work for AI crawlers like GPTBot and PerplexityBot. They fetch your HTML without executing JavaScript, so a redirect loop or error a browser tolerates can still cost you a citation.

</tip>

## Recovery Timeline

![Migration Recovery Timeline](/images/learn-seo/vue/migration-recovery-gantt.svg)

Recovery is slower than most guides suggest. Across 1,052 tracked domain migrations, [SALT.agency found](https://salt.agency/blog/27-of-domain-migrations-recover-in-90-days/) that 5% of sites recovered within 30 days, 23% within 90 days, 35% within 180 days, and 60% within a year; the median recovery time was 304 days, the mean 489 days. A separate [Search Engine Journal study of 892 migrations](https://www.searchenginejournal.com/study-how-long-should-seo-migration-take/492050/) found a mean recovery time of 523 days, with 17% never fully recovering after 1,000 days, an improvement on the 42% non-recovery rate from its earlier, smaller study.

**Week 1-2**: a traffic dip of [10-30% is normal](https://www.searchenginejournal.com/what-is-a-migration-hangover-traffic-drop-how-do-you-avoid-it/575102/) while Google discovers your redirects and starts reindexing.

**Weeks 3 onward**: small, clean migrations often recover faster than large ones, and [local SEO data puts a typical full-recovery range at 30-60 days](https://www.localseoguide.com/how-long-does-it-take-to-recover-from-a-domain-migration/) for smaller sites. The SALT.agency and Search Engine Journal numbers above are the more realistic baseline for anything larger.

**Beyond 3 months**: if traffic still hasn't recovered, audit for missing redirects (check the Page Indexing report for 404s), redirect chains, canonical tags still pointing at old URLs, and internal links still pointing at old URLs.

**Keep redirects for at least a year.** [Google's guidance](https://developers.google.com/search/docs/crawling-indexing/site-move-with-url-changes) is to keep them "for as long as possible, generally at least 1 year," and indefinitely if a URL still gets traffic. That's separate from the Change of Address tool's 180-day signal-forwarding window: the tool speeds up the transition, the redirects themselves are what makes it permanent.

## Common Migration Mistakes

**Redirect chains**: dilute authority with every hop. [Consolidate old and new redirects](https://developers.google.com/search/docs/crawling-indexing/301-redirects) into single-hop redirects.

**Forgetting internal links**: your site's own internal links still point at old URLs, triggering unnecessary redirects on every click. Update them to point directly at new URLs.

**Not updating canonical URLs**: canonical tags create loops when they point at redirected URLs. Update canonicals alongside redirects, not after.

**Removing redirects too early**: traffic sources outside your control (old backlinks, bookmarks, third-party sites) use old URLs indefinitely. Keep redirects for years, not months.

**Client-side redirects**: JavaScript redirects (`window.location`) don't pass ranking signals, and Google may not follow them at all. SEO requires server-side 301s.

**No redirect testing**: test redirects on staging before launch. Verify each returns 301 and resolves to 200 in one hop.

**Forgetting mobile/AMP URLs**: if you had separate mobile URLs (`m.example.com`) or AMP versions, redirect those too.

## Using Nuxt?

Nuxt applications should use [server middleware for redirects](/learn-seo/nuxt/controlling-crawlers/redirects). One thing to watch: Nuxt's `routeRules` string shorthand (`redirect: '/new-url'`) defaults to a 307 temporary redirect, not a permanent one; use the object form (`{ redirect: { to: '/new-url', statusCode: 301 } }`) for a real migration redirect.

For full Nuxt migration guides, see the [Launch & Listen section](/learn-seo/nuxt/launch-and-listen).

## Checklist

<checklist id="site-migration-vue">

- Crawl the old site and export every URL before touching production
- Build a redirect mapping spreadsheet: old URL, new URL, target status code
- Implement server-side 301 redirects, never client-side
- Point every redirect directly at its final destination, no chains
- Update all canonical tags and internal links to the new URLs
- File the Change of Address tool in Search Console for domain changes
- Submit the new sitemap and remove the old one
- Check the Page Indexing report daily for the first two weeks
- Keep redirects live for at least a year

</checklist>
