---
title: "HTTP Redirects for SEO in Nuxt"
description: "301 redirects preserve SEO value when content moves. Nuxt handles server-side redirects through routeRules to pass link equity and maintain rankings."
canonical_url: "https://nuxtseo.com/learn-seo/nuxt/controlling-crawlers/redirects"
last_updated: "2026-01-29"
---

<key-takeaways>

- 301 redirects pass ~100% link equity. use for permanent content moves
- In 2026, redirects are critical for preserving visibility in AI search during migrations
- Server-side redirects required. JavaScript redirects don't pass SEO value
- Avoid redirect chains (A→B→C). redirect directly to the final destination

</key-takeaways>

301 redirects pass nearly 100% of link equity to the new URL, preserving your SEO value and **AI Search Visibility** when content moves. In 2026, a botched migration without proper redirects can lead to a total loss of citation in AI-generated answers.

Use for permanent moves: site migrations, URL restructuring, domain changes, deleted pages with replacements. For duplicate content use [canonical tags](/learn-seo/nuxt/controlling-crawlers/canonical-urls). For temporary moves use 302 redirects.

## Quick Setup

Nuxt handles redirects through `routeRules` in your config or server middleware:

<code-group>

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  routeRules: {
    '/old-page': { redirect: { to: '/new-page', statusCode: 301 } },
    '/blog/**': { redirect: '/articles/**' }
  }
})
```

```ts [server/middleware/redirects.ts]
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)
  }
})
```

</code-group>

## 301 vs 302 Redirects

### When to Use Each

**301 (Permanent)** - Transfers ~100% of link equity to new URL ([Google](https://www.searchenginejournal.com/301-redirect-pagerank/275503/))

- Permanent content moves
- Domain migrations
- URL structure changes
- Deleted pages with direct replacements
- HTTP to HTTPS upgrades

**302 (Temporary)** - Keeps SEO value on original URL

- A/B testing
- Temporary promotions
- Maintenance pages
- Out-of-stock product redirects

If a 302 stays active for months with no plans to revert, switch to 301 ([SEO Clarity](https://www.seoclarity.net/resources/knowledgebase/use-301-redirect-vs-302-redirect-15683/)). 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.

### How Long to Keep Redirects Active

Google recommends keeping 301 redirects active for at least one year ([Search Central](https://www.searchenginejournal.com/google-keep-301-redirects-in-place-for-a-year/428998/)). This ensures Google transfers all ranking signals and recrawls links pointing to old URLs.

Keep redirects longer if:

- External sites still link to old URLs
- Old URLs receive referral traffic
- High-value pages with many backlinks

Removing redirects before Google processes them loses the transferred SEO value permanently.

### Avoid Redirect Chains

Redirect chains (A → B → C) waste [crawl budget](/learn-seo/nuxt/controlling-crawlers#crawler-budget) and slow page speed ([Gotch SEO](https://www.gotchseo.com/redirect-chains/)). Each hop degrades [Core Web Vitals](/learn-seo/nuxt/launch-and-listen/core-web-vitals), particularly LCP and TTFB.

Google follows up to 5 redirect hops, then aborts ([Hike SEO](https://developers.google.com/search/docs/crawling-indexing/301-redirects#redirect-chains)). Redirect directly to final destination:

Bad:

```plaintext
/old → /interim → /final
```

Good:

```plaintext
/old → /final
/interim → /final
```

## Common Patterns

### Domain Migration

<code-group>

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  routeRules: {
    // Redirect entire old domain to new domain
    '/**': {
      redirect: {
        to: 'https://new-domain.com/**',
        statusCode: 301
      }
    }
  }
})
```

```ts [server/middleware/domain.ts]
export default defineEventHandler((event) => {
  const host = getRequestHost(event)
  if (host === 'old-domain.com') {
    return sendRedirect(event, `https://new-domain.com${event.path}`, 301)
  }
})
```

</code-group>

### URL Structure Changes

<code-group>

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  routeRules: {
    '/old': { redirect: { to: '/new', statusCode: 301 } },
    '/blog/**': { redirect: '/articles/**' },
    '/products/**': { redirect: '/shop/**' }
  }
})
```

```ts [server/middleware/redirects.ts]
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)
  }
})
```

</code-group>

### HTTPS Enforcement

<code-group>

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  routeRules: {
    '/**': {
      headers: {
        'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'
      }
    }
  }
})
```

```ts [server/middleware/https.ts]
export default defineEventHandler((event) => {
  if (getHeader(event, 'x-forwarded-proto') !== 'https') {
    const host = getRequestHost(event)
    return sendRedirect(event, `https://${host}${event.path}`, 301)
  }
})
```

</code-group>

Learn more about HTTPS in our [security guide](/learn-seo/nuxt/routes-and-rendering/security).

### WWW Standardization

<code-group>

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  routeRules: {
    '/**': {
      redirect: {
        to: (path, { host }) => {
          if (!host?.startsWith('www.')) {
            return `https://www.${host}${path}`
          }
        },
        statusCode: 301
      }
    }
  }
})
```

```ts [server/middleware/www.ts]
export default defineEventHandler((event) => {
  const host = getRequestHost(event)
  if (!host.startsWith('www.')) {
    return sendRedirect(event, `https://www.${host}${event.path}`, 301)
  }
})
```

</code-group>

## Testing Redirects

Verify redirects work correctly before deploying:

1. **Check status code** - Use browser dev tools Network tab, confirm 301 or 302
2. **Test destination** - Ensure redirect points to correct final URL
3. **Verify no chains** - Confirm single hop to destination
4. **Test trailing slashes** - Check with and without trailing slash
5. **Check query parameters** - Verify parameters carry over if needed

### Tools

- [Google Search Console](https://search.google.com/search-console) - Monitor crawl errors and redirect issues
- Browser Dev Tools Network tab - Check status codes and headers
- [Screaming Frog](https://www.screamingfrog.co.uk/seo-spider/) - Bulk redirect testing and chain detection
- curl - `curl -I https://example.com/old-page` shows redirect headers

## Common Mistakes

### Redirecting to Irrelevant Pages

Redirecting deleted pages to your homepage damages SEO and user experience. Google may treat this as a soft 404, ignoring link equity transfer ([Victorious](https://developers.google.com/search/docs/crawling-indexing/soft-404-errors)).

```ts [nuxt.config.ts]
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' }
  }
})
```

### Redirect Loops

Circular redirects break your site:

```ts [nuxt.config.ts]
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' }
  }
})
```

### Using Client-Side Redirects for SEO

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.

### Not Updating Internal Links

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.
