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.
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.
Start here before touching production:
For large sites (10,000+ pages), consider migrating in sections. Test with a small section first, verify traffic holds, then migrate the rest.
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.
Nuxt handles redirects through routeRules in nuxt.config.ts. These are server-side redirects that properly pass PageRank.
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/old-url': { redirect: '/new-url' },
'/company/about': { redirect: '/about' }
}
})
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/blog/**': { redirect: '/articles/**' },
'/old-section/**': { redirect: '/new-section/**' }
}
})
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)
}
})
// 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)
}
})
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).
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.
The hour after migration is critical.
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:
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.