Creating Redirects With Nuxt 3
Dealing with redirects is only a matter of time, at some point you're going to need them. In this post we'll explore different ways of creating redirects in your Nuxt application.
Why You Should Care About Redirects
- SEO: Redirects are very important when transferring link equity from one website to another if a page moves from the old site to the new.
- Backlinks: If your site has been around for a while, hopefully people have linked to it. Think of all of the years people have shared your site in forums, emails, or social media. You really want all of those links to keep working, otherwise people clicking on them will bail.
- Security: If a user doesn't have access to a page a redirect should send them to the login page.
Server-Side Redirects
The best way to use redirects are on the server so you can return proper HTTP status codes. When running Nuxt with Server-Side Rendering (SSR), you can use Server Middleware, Middleware, or Route Rules.
Server Middleware
This is code ran only on a Nuxt server. If you are creating redirects for SEO or backlinks then you don't need client-side redirects. Creating most of your redirects on the server will declutter your client-side experience and keep it performant. In general, only use middleware if you have no other choice.
To create Server Middleware, create a file under /server/middleware
. Nuxt will automatically import the file and use it for all routes. Your file should export a function using defineEventHandler
. It gets passed an event object that contains all the information you need.
export default defineEventHandler((event) => {
console.log('New request: ' + getRequestURL(event))
})
H3 Composables
Nuxt's internal server (H3) has a bunch of helper composables built right in! They are really handy for launching redirects, parsing urls, and even working with cookies!
- readBody - Reads the body of the event payload and tries to convert to JSON of possible.
- getRequestURL - Returns an object of the url parts for the event
- getCookie - Gets a cookie value for a given key
- sendRedirect - Sends a redirect response
- Plus MANY more, see the full list
Handling Error Routes
Before we go further I should mention that there is a funky url you will have to contend with, the error route. It's an internal way Nitro/H3 handles sending errors around. You will see hits like this in your middleware handler.
https://my.app/__nuxt_error?url=/foo-bar/&statusCode=404&statusMessage=Page+not+found:+/foo-bar/&message=Page+not+found:+/foo-bar/&stack
You have to make sure to not redirect these types of url hits, otherwise 404 pages (and more) will get messed up.
General Redirect Template
export default defineEventHandler(async (event) => {
const urlObj = getRequestURL(event)
// don't touch error routes
if (urlObj.pathname === '/__nuxt_error') return
// detect other conditions and redirect to a new url
await sendRedirect(event, '/some-new-url', 301)
})
Following this pattern, here are some handy redirect rules.
Redirect One Url
// redirects /old-page -> /new-page
if (urlObj.pathname == '/old-page') {
await sendRedirect(event, '/new-page')
}
Force Lowercase Urls
// redirects /Products -> /products
if (urlObj.pathname.match(/[A-Z]/)) {
urlObj.pathname = urlObj.pathname.toLowerCase()
await sendRedirect(event, urlObj.href)
}
Force Ending Slash
// redirects /products -> /products/
// don't redirect files
if (urlObj.pathname.indexOf('.') == -1 && !urlObj.pathname.endsWith('/')) {
urlObj.pathname += '/'
await sendRedirect(event, urlObj.href)
}
Map Old Domain To New
// redirects /products -> http://newsite.com/products
const oldDomain = 'www.old-site.net'
const newDomain = 'newsite.com'
if (event.node.req.headers.host == oldDomain) {
await sendRedirect(event, event.node.req.href.replace(oldDomain, newDomain))
}
Force SSL
// redirects http://cool-site.com -> https://cool-site.com
if (urlObj.protocol === 'http') {
urlObj.protocol = 'https'
await sendRedirect(event, urlObj.href)
}
Middleware
The second way to enforce redirects is through route middleware. Here things get a little tricky as it's ran both server-side and client-side. Middleware is located in the /middleware/ directory and is auto imported. If you want middleware to run on every route, just added .global
to the filename (ex: foo.global.ts
).
Composables
- navigateTo - redirects to another page
- abortNavigation - aborts the navigation with an optional error message
Named Middleware
// This will be named middleeware called 'foo-bar'
export default defineNuxtRouteMiddleware((to, from) => {
if (to.path !== '/') return navigateTo('/')
})
Use On Pages
<script lang="ts">
definePageMeta({
middleware: ['foo-bar'],
})
</script>
Inline Middleware
<script setup>
definePageMeta({
middleware: [
function (to, from) {
// do something
}
]
})
</script>
Route Rules (Experimental!)
You can create redirects using simple route rules in your nuxt config file. These rules ARE compatible with Netlify and Vercel!
export default defineNuxtConfig({
routeRules:{
'/old-page': { redirect: '/new-page' }, // 307 (temp redirect)
'/old-page': { redirect: { to: '/new-page', statusCode: 301 } },
'/old-path/**': { redirect: '/new-page '}, // redirect old-path/(any) to /new-page
}
})
Native Redirects With Static Sites
Popular hosting providers also provide a way to create redirects within their server environment. Usually this involves adding a specially named file to your repo that they will read when they build your site.
Redirect To Wrapping This Up
Ok, I feel like I've beaten this thing to death. Redirects are a small pain, and just like tupperware magically seem to multiply overnight. With the techniques above you should be able to manage the chaos and keep your site running smoothly.
Holy crap, I can't believe you are still reading this far. Did I miss anything in this post? Did I get anything wrong? Drop me a line in the contact page.