---
title: "Site Migration SEO for Vue Apps"
description: "Map Vue app URL moves, test permanent HTTP redirects, and monitor canonical and discovery changes without a fixed recovery deadline."
canonical_url: "https://nuxtseo.com/learn-seo/vue/launch-and-listen/site-migration"
last_updated: "2026-10-08"
---

> Index of every page on this site: [llms.txt](https://nuxtseo.com/llms.txt)

::key-takeaways
- Map moved URLs to relevant replacements with permanent HTTP redirects. Preserve unchanged URLs; use 404/410 when no relevant replacement exists
- Recovery and traffic changes vary by migration. Google publishes no universal recovery percentage or deadline
- Use Change of Address after eligible domain/subdomain moves and redirects. Its 180-day site-signal window differs from Google’s at-least-year redirect guidance
- 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 available globally since August 31, 2026.
::

A migration can disrupt discovery, links, and search appearance. Map URL outcomes, test redirects, and monitor processing. A citation or ranking is not guaranteed to carry over.

## Types of Migrations

Each migration type affects SEO differently:

**Domain change** ([old.com](http://old.com) → [new.com](http://new.com)): file the [Change of Address tool](https://support.google.com/webmasters/answer/9370220) in Search Console after an eligible domain or subdomain move. Verify both properties with the same account. A submission does not move subdomains automatically. The tool forwards site signals for 180 days; keep HTTP redirects much longer.

**Protocol change** (HTTP → HTTPS): update every canonical tag to the HTTPS version. Conflicting preferences do not themselves create a redirect loop. Update the signals consistently; Change of Address does not apply to this protocol-only move.

**URL structure change** (`/blog/post` → `/posts/post`): map each moved URL to a relevant replacement, with no intermediate hops. Change of Address does not apply to a path-only move.

**Platform/framework change**: compare old and new published inventories. Record unchanged paths and any moved or removed content. A framework change alone does not require different URLs.

**Site redesign with the same URLs**: unchanged URLs need no move redirects. Validate content, 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. Combine the crawl with the publishing inventory; a crawl can miss unlinked URLs.
2. **Save available Search Console observations.** Export available page-indexing examples and Performance data. These reports are not an exhaustive inventory of indexed URLs; compare them with the crawl and publishing inventory. Applicable Search Console Performance history covers [16 months](https://gscdump.com/learn-google-search-console/limits/16-month-data-retention), so the pre-migration numbers age out if you don't save them.
3. **Document current rankings.** Export Search Console Performance for your top pages so you have something to compare against after launch. Add a [Search Console annotation](https://gscdump.com/learn-google-search-console/performance/custom-annotations) on launch day so the change sits beside the traffic chart.
4. **Build a redirect mapping spreadsheet.** Three columns: Old URL, New URL, target status code. Record each URL as unchanged, redirected to a relevant replacement, or removed with 404/410.

For large sites, [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.

```
/blog/vue-seo-guide → /guides/vue-seo
/products/item-123 → unchanged URL, no redirect
```

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

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

**Deleted pages**: redirect to a relevant replacement when one exists. Otherwise return 404 or 410. Previous traffic or backlinks do not justify an unrelated redirect.

## Implementing Redirects in Vue

[Google prefers permanent HTTP redirects](https://developers.google.com/search/docs/crawling-indexing/301-redirects) for permanent moves; Google supports 301 and 308. Google can process some JavaScript redirects, but those depend on rendering. Vue does not own the HTTP response; implement moves in the host or application server.

### Express Server

Install Express in your app’s server project. This setup targets Express 5.2.1 and belongs before the existing Vue SSR/static handler. Deploy domain-move rules on the old host. The example retains query strings by app policy and encodes the captured slug as one path segment; change that policy deliberately if needed.

```bash
pnpm add express
```

```ts
import express from 'express'

const app = express()

function withQuery(targetPath: string, originalUrl: string) {
  const query = new URL(originalUrl, 'https://old.example.com').search
  return `${targetPath}${query}`
}

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

app.get('/blog/:slug', (req, res) => {
  const target = `/posts/${encodeURIComponent(req.params.slug)}`
  res.redirect(301, withQuery(target, req.originalUrl))
})

const redirects: Record<string, string> = {
  '/old-page-1': '/new-page-1',
  '/old-page-2': '/new-page-2',
  '/company/about': '/about'
}

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

These handlers do not start a server or supply destination pages. Keep your app’s existing listener and rendering handler. Verify real destination responses separately.

### Vite Server

Vite’s development server is not your production redirect layer. Configure redirects on the actual deployed host or use the Express integration above. Verify HTTP responses against that deployment.

### H3 Server (Nitro/Nuxt)

If the Vue app uses an H3/Nitro backend, follow the [checked Nuxt redirect guide](https://nuxtseo.com/learn-seo/nuxt/controlling-crawlers/redirects) for its released handler and route-rule boundaries. Plain Vue does not supply Nitro middleware or a server directory automatically.

## 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 hop adds a request and can delay navigation. Do not assign a fixed ranking loss to a hop.

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 permanent move should return 301 or 308 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 to a redirected URL sends an indirect preference; it does not itself create an HTTP loop. Point to the intended current equivalent URL.

```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">
```

This setup excerpt requires Unhead installed on the Vue app and runs inside a component setup. A fixed URL is appropriate only for that specific page:

```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 eligible domain/subdomain moves, use [Change of Address](https://support.google.com/webmasters/answer/9370220) after redirects are live. It forwards site signals for 180 days. Exclude protocol, path, and www-only moves.
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 infrequent, important changes. A request does not guarantee crawling or indexing.
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 available globally since August 31, 2026, 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. Provider capabilities vary. Inspect their documented access requirements and actual HTTP responses; a bot-like user agent does not prove a provider fetch or citation.
::

## Recovery Timeline

Google processes moves on its own schedule. Traffic and indexing changes vary by migration. Inspect response failures, canonical preferences, links, and reported indexing states rather than expecting a fixed percentage dip or deadline.

**Keep redirects for at least a year.** [Google’s guidance](https://developers.google.com/search/docs/crawling-indexing/site-move-with-url-changes) recommends keeping them as long as possible, generally at least one year. Keep useful old links working longer. This differs from Change of Address’s 180-day site-signal window.

[Reported site-move observations](https://www.seroundtable.com/google-crawling-indexing-serving-data-42225.html) put typical processing at 1 to 3 months, with slow cases reaching 6 months to over a year. These figures do not promise traffic recovery. Keep checking redirects and dated URL observations; [Google Search timelines](https://nuxtseo.com/learn-seo/google-search-timelines) explains the separate processing stages.

## Common Migration Mistakes

**Redirect chains**: add requests and delay navigation. [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 should point at the intended current equivalent URL; a redirected preference does not itself create an HTTP loop. 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**: use permanent HTTP redirects for permanent moves when possible. JavaScript redirects depend on rendering; they are not equivalent to an immediate HTTP 301/308.

**No redirect testing**: test redirects on staging before launch. Verify each returns 301 or 308 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](https://nuxtseo.com/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](https://nuxtseo.com/learn-seo/nuxt/launch-and-listen).

## Checklist

::checklist{#site-migration-vue}
- Combine an old-site crawl with the publishing inventory before touching production
- Build a redirect mapping spreadsheet: old URL, new URL, target status code
- Implement permanent HTTP 301/308 redirects for permanent moves where possible
- Point every redirect directly at its final destination, no chains
- Update all canonical tags and internal links to the new URLs
- Use Change of Address after eligible domain/subdomain moves; exclude protocol, path, and www-only moves
- 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
::

## Sitemap

See the full [sitemap](https://nuxtseo.com/sitemap.md) for all pages.
