Handling Nuxt Route Changes During Site Migration
Problem Statement
You are restructuring routes in a Nuxt 3 application during a migration and need old paths to 301 to their new locations without a client-side flash or a broken crawl. Nuxt 3 runs on the Nitro server engine, which means redirects can be declared statically as routeRules in nuxt.config or computed dynamically in Nitro server middleware. This page is part of CMS & Framework Routing Changes and covers both paths.
When to Use This Approach
- Your front end is Nuxt 3 (or Nuxt Bridge) and you control
nuxt.config. - You are renaming route segments or collapsing route groups during the migration.
- You want server-rendered 301s, not client-side
navigateToredirects that flash a page first. - Some redirects must read the incoming request (host, header, locale) and so need Nitro middleware.
- You are moving the Nuxt app to a new domain alongside the route changes.
Step-by-Step Instructions
1. Declare Static Redirects with routeRules
routeRules in nuxt.config are applied by Nitro before the page component runs, so they emit a true server-side redirect. Use a redirect object with an explicit statusCode.
// nuxt.config.ts — Nitro applies these on the server, no component render
export default defineNuxtConfig({
routeRules: {
'/blog/**': { redirect: { to: '/articles/**', statusCode: 301 } },
'/promo': { redirect: { to: '/offers', statusCode: 302 } },
},
});
2. Preserve Path Segments with Wildcards
The ** wildcard captures the remainder of the path so a single rule can cover an entire legacy section instead of one rule per URL.
// One rule migrates the whole /docs tree to /help
routeRules: {
'/docs/**': { redirect: { to: '/help/**', statusCode: 301 } },
}
3. Handle Dynamic Cases with Nitro Server Middleware
When a redirect depends on the request — host during a multi-domain move, a header, or a locale cookie — use a Nitro server middleware file under server/middleware/. sendRedirect issues the response before rendering.
// server/middleware/redirect.ts — redirect requests on the old host
export default defineEventHandler((event) => {
const host = getRequestHeader(event, 'host');
if (host === 'old.example.com') {
const url = getRequestURL(event);
return sendRedirect(event, `https://www.example.com${url.pathname}${url.search}`, 301);
}
});
4. Keep Query Strings Intact
sendRedirect does not append the query string for you — read it from the request URL and pass it through, as ${url.search} above. For routeRules, the wildcard target preserves the captured path but confirm parameters survive in testing.
// Append the original query string explicitly so trackers survive
const target = `/articles${url.pathname.replace('/blog', '')}${url.search}`;
return sendRedirect(event, target, 301);
Worked Example
A Nuxt 3 site moving /blog to /articles and changing host. With the routeRules wildcard plus the host middleware deployed:
$ curl -sIL https://old.example.com/blog/nuxt-migration?ref=newsletter
HTTP/1.1 301 Moved Permanently
location: https://www.example.com/articles/nuxt-migration?ref=newsletter
HTTP/1.1 200 OK
The request resolves in a single server-side 301, the ref parameter is preserved, and no client-side render flashes the old page first. Order matters: the host middleware runs first to fix the domain, and the route rename is handled by routeRules on the new host.
Verification
- Confirm a single server-side hop:
curl -sIL https://old.example.com/blog/nuxt-migration | grep -iE '^HTTP|^location'. - Verify no client-side redirect by checking the status is 301 in the headers, not a 200 with a JS navigation.
- Re-crawl the legacy route tree and confirm the query string survives on parameterised URLs.
FAQ
Should I use routeRules or server middleware for Nuxt redirects?
Use routeRules for static, request-independent path changes — they are declarative and easy to audit. Use Nitro server middleware only when the redirect must read the request (host, header, locale), as in a multi-domain move.
Why not redirect in the page component with navigateTo?
A component-level redirect runs after the page starts rendering, which can flash the old content and is not a clean server-side 301 for crawlers. Prefer routeRules or Nitro middleware so the redirect happens before render.
Related
- CMS & Framework Routing Changes
- Configuring Next.js Redirects During Domain Migration
- Redirect Chain Elimination
← Back to CMS & Framework Routing Changes