Site Migration SEO for Nuxt Apps

Migrate domains, redesign URLs, or switch frameworks without losing search rankings.
Harlan WiltonHarlan Wilton12 mins read Published

Site migrations lose search rankings when done wrong. Well-executed migrations recover 90-95% of traffic within 30 days. Poor migrations can take 6-12 months to recover or never reach previous levels.

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

Types of Migrations

Each migration type affects SEO differently:

Domain change (old.com → new.com): Requires Change of Address tool in Google Search Console and strict 1:1 URL mapping. Keep redirects for at least one year.

Protocol change (HTTP → HTTPS): Update all canonical tags to HTTPS versions. Forgetting this creates redirect loops—redirects send Google to HTTPS, but canonicals point back to HTTP.

URL structure change (/blog/post → /posts/post): Most prone to redirect chains. Map every old URL to exactly one new URL. No intermediates.

Platform/framework change: Moving from WordPress to Nuxt, or Vue to Nuxt. URL structure usually changes. Full redirect mapping required.

Site redesign with same URLs: Lowest risk if URLs stay identical. Still validate canonical tags and internal links.

Pre-Migration Checklist

Start here before touching production:

  1. Crawl old site completely: Use Screaming Frog or similar to export all URLs. You need a full inventory.
  2. Export indexed URLs from Search Console: Go to Coverage report → Valid → Export. These are URLs Google knows about.
  3. Document current rankings: Screenshot Search Console Performance for top pages. You'll compare against this.
  4. Create redirect mapping spreadsheet: Three columns: Old URL | New URL | Status (200, 301, 410). Map every single URL. No exceptions.

For large sites (10,000+ pages), consider migrating in sections. Test with a small section first, verify traffic holds, then migrate the rest.

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 → /products/item-123 (unchanged)

Pattern-based redirects: For systematic URL changes. Use regex or route patterns to redirect entire sections.

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

Deleted pages: Don't 404 pages that had traffic or backlinks. Redirect to the most relevant alternative. If truly no alternative exists, return 410 (Gone) instead of 404—signals permanent removal.

Implementing Redirects in Nuxt

Nuxt handles redirects through routeRules in nuxt.config.ts. These are server-side redirects that properly pass PageRank.

Single Redirects

// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/old-url': { redirect: '/new-url' },
    '/company/about': { redirect: '/about' }
  }
})

Pattern-Based Redirects

// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/blog/**': { redirect: '/articles/**' },
    '/old-section/**': { redirect: '/new-section/**' }
  }
})

Bulk Redirects with Server Middleware

For large redirect maps (1000+ URLs), use server middleware:

// server/middleware/redirects.ts
const redirects: Record<string, string> = {
  '/old-page-1': '/new-page-1',
  '/old-page-2': '/new-page-2',
  '/products/legacy-item': '/products/new-item'
}

export default defineEventHandler((event) => {
  const path = event.path
  const redirect = redirects[path]

  if (redirect) {
    return sendRedirect(event, redirect, 301)
  }
})

For even larger redirect maps, load from JSON:

// server/middleware/redirects.ts
import redirectData from '~/redirects.json'

export default defineEventHandler((event) => {
  const redirect = redirectData[event.path]

  if (redirect) {
    return sendRedirect(event, redirect, 301)
  }
})

Dynamic Pattern Redirects

// server/middleware/redirects.ts
export default defineEventHandler((event) => {
  const path = event.path

  // Redirect old blog structure to new
  if (path.startsWith('/blog/')) {
    const slug = path.replace('/blog/', '')
    return sendRedirect(event, `/articles/${slug}`, 301)
  }

  // Redirect category pages with pagination
  const categoryMatch = path.match(/^\/category\/([^/]+)\/page\/(\d+)$/)
  if (categoryMatch) {
    const [, category, page] = categoryMatch
    return sendRedirect(event, `/c/${category}?page=${page}`, 301)
  }
})

Avoid Redirect Chains

Redirect chains happen when URL A redirects to B, which redirects to C. This dilutes PageRank and slows crawling.

Common scenario: You have old redirects (A → B) and add new migration redirects (B → C). Result: chain A → B → C.

Fix: Update all redirects to point directly to final destination. Consolidate old and new redirects into single-hop redirects.

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

// Good: consolidate in routeRules
export default defineNuxtConfig({
  routeRules: {
    '/page-v1': { redirect: '/page-v3' }, // direct to final
    '/page-v2': { redirect: '/page-v3' }
  }
})

Test redirects before launch: Each should return 301 status and resolve in one hop to 200 (OK).

Update Canonical Tags

When URLs change, canonical tags must point to new URLs. Canonical pointing to redirect is a common migration mistake.

After migration, canonical tags should reference new URL structure:

<!-- 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 Nuxt with useHead:

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

Or with useSeoMeta:

<script setup>
useSeoMeta({
  canonicalUrl: 'https://example.com/new-url'
})
</script>

Scan staging site before launch to verify all canonicals point to new URLs, not old ones.

Post-Migration Steps

The hour after migration is critical.

  1. Update Search Console property: For domain changes, use Change of Address tool. This tells Google you've moved.
  2. Submit new sitemap: Generate sitemap with new URLs. Submit in Search Console. Remove old sitemap from robots.txt.
  3. Request indexing of key pages: In Search Console, request indexing for homepage and top 10-20 pages. Speeds up discovery.
  4. Monitor coverage report: Check daily for errors. Look for 404s, soft 404s, redirect errors, or pages not followed.
  5. Watch server capacity: Google crawls more after migrations. Redirects from old URLs trigger crawls of new URLs. Monitor server load.
  6. Check Analytics segmentation: Set up date comparison in Google Analytics—before migration vs after. Track organic traffic specifically.

Recovery Timeline

Expect these phases:

Week 1-2: Traffic dip of 10-25% is normal. Google discovers redirects and starts reindexing.

Week 3-4: Small sites recover 90%+ of traffic if migration was clean. Large sites still reindexing.

Month 2-3: Most sites reach full recovery. Rankings stabilize. Typical range is 30-60 days.

Month 4-6: Large sites (100,000+ pages) continue recovery. Average across 892 migrations was 523 days—but median is much lower.

Keep redirects for 1+ year: Google recommends at least 12 months. Longer if you still see traffic to old URLs. Never remove redirects that still get hits.

If traffic hasn't recovered after 3 months, audit for:

  • Missing redirects (404s in coverage report)
  • Redirect chains
  • Canonical tags still pointing to old URLs
  • Internal links still pointing to old URLs

Common Migration Mistakes

Redirect chains: As mentioned, these dilute authority. Consolidate old and new redirects into single-hop redirects.

Forgetting internal links: Your site's internal links still point to old URLs, triggering unnecessary redirects. Update internal links to point directly to new URLs.

Not updating canonical URLs: Canonical tags create loops when they point to redirected URLs. Update canonicals alongside redirects.

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 PageRank. Google may not follow them. Server-side 301s are required.

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.