301 redirects pass nearly 100% of link equity to the new URL (Google confirms), preserving your SEO value when content moves. Server-side implementation required for search engines to recognize them.
Use for permanent moves: site migrations, URL restructuring, domain changes, deleted pages with replacements. For duplicate content use canonical tags. For temporary moves use 302 redirects.
Nuxt handles redirects through routeRules in your config or server middleware:
export default defineNuxtConfig({
routeRules: {
'/old-page': { redirect: { to: '/new-page', statusCode: 301 } },
'/blog/**': { redirect: '/articles/**' }
}
})
export default defineEventHandler((event) => {
if (event.path === '/old-page') {
return sendRedirect(event, '/new-page', 301)
}
if (event.path.startsWith('/blog/')) {
const slug = event.path.replace('/blog/', '')
return sendRedirect(event, `/articles/${slug}`, 301)
}
})
301 (Permanent) - Transfers ~100% of link equity to new URL (Google)
302 (Temporary) - Keeps SEO value on original URL
If a 302 stays active for months with no plans to revert, switch to 301 (SEO Clarity). Search engines may eventually treat long-term 302s as permanent anyway.
307/308 - Like 302/301 but preserve HTTP method (POST remains POST). Rarely needed for typical SEO work.
Google recommends keeping 301 redirects active for at least one year (Search Central). This ensures Google transfers all ranking signals and recrawls links pointing to old URLs.
Keep redirects longer if:
Removing redirects before Google processes them loses the transferred SEO value permanently.
Redirect chains (A → B → C) waste crawl budget and slow page speed (Gotch SEO). Each hop degrades Core Web Vitals, particularly LCP and TTFB.
Google follows up to 5 redirect hops, then aborts (Hike SEO). Redirect directly to final destination:
Bad:
/old → /interim → /final
Good:
/old → /final
/interim → /final
export default defineNuxtConfig({
routeRules: {
// Redirect entire old domain to new domain
'/**': {
redirect: {
to: path => `https://new-domain.com${path}`,
statusCode: 301
}
}
}
})
export default defineEventHandler((event) => {
const host = getRequestHost(event)
if (host === 'old-domain.com') {
return sendRedirect(event, `https://new-domain.com${event.path}`, 301)
}
})
export default defineNuxtConfig({
routeRules: {
'/old': { redirect: { to: '/new', statusCode: 301 } },
'/blog/**': { redirect: '/articles/**' },
'/products/**': { redirect: '/shop/**' }
}
})
export default defineEventHandler((event) => {
if (event.path === '/old') {
return sendRedirect(event, '/new', 301)
}
if (event.path.startsWith('/blog/')) {
const slug = event.path.replace('/blog/', '')
return sendRedirect(event, `/articles/${slug}`, 301)
}
if (event.path.startsWith('/products/')) {
const id = event.path.replace('/products/', '')
return sendRedirect(event, `/shop/${id}`, 301)
}
})
export default defineNuxtConfig({
routeRules: {
'/**': {
headers: {
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'
}
}
}
})
export default defineEventHandler((event) => {
if (getHeader(event, 'x-forwarded-proto') !== 'https') {
const host = getRequestHost(event)
return sendRedirect(event, `https://${host}${event.path}`, 301)
}
})
Learn more about HTTPS in our security guide.
export default defineNuxtConfig({
routeRules: {
'/**': {
redirect: {
to: (path, { host }) => {
if (!host?.startsWith('www.')) {
return `https://www.${host}${path}`
}
},
statusCode: 301
}
}
}
})
export default defineEventHandler((event) => {
const host = getRequestHost(event)
if (!host.startsWith('www.')) {
return sendRedirect(event, `https://www.${host}${event.path}`, 301)
}
})
Verify redirects work correctly before deploying:
curl -I https://example.com/old-page shows redirect headersRedirecting deleted pages to your homepage damages SEO and user experience. Google may treat this as a soft 404, ignoring link equity transfer (Victorious).
export default defineNuxtConfig({
routeRules: {
// ❌ Bad - mass redirects to homepage
'/blog/**': { redirect: '/' },
// ✅ Good - redirect to relevant content
'/blog/vue-tips': { redirect: '/articles/vue-tips' },
'/blog/seo-guide': { redirect: '/articles/seo-guide' }
}
})
Circular redirects break your site:
export default defineNuxtConfig({
routeRules: {
// ❌ Bad - creates infinite loop
'/page-a': { redirect: '/page-b' },
'/page-b': { redirect: '/page-a' },
// ✅ Good - both redirect to final destination
'/page-a': { redirect: '/final' },
'/page-b': { redirect: '/final' }
}
})
JavaScript redirects don't pass link equity reliably. Search engines may not execute JavaScript before indexing. Always use server-side redirects (301/302 status codes) for SEO purposes.
Relying on redirects for internal links wastes server resources and slows page speed. Update internal links to point directly to new URLs, keep redirects for external links and old bookmarks.
Canonical Link Tag
Canonical URLs tell search engines which version of a page to index when duplicate content exists. Here's how to set them up in Nuxt.
Duplicate Content
Duplicate content wastes crawl budget and splits ranking signals. Here's how to find and fix it with canonical tags, redirects, and parameter handling.