Discover all the ways to implement redirects in Nuxt with this comprehensive guide. Learn about server-side, universal, and client-side redirects, along with their pros and cons. Check out the full demo app showcasing each method to see practical examples in action.
Get notified when we release new tutorials, lessons, and other expert Nuxt content.
There are a lot of ways to do a redirect in Nuxt, with pros and cons to each option.
I took the time to go through and thoroughly document every single way possible. I also created a demo app that showcases multiple variations of each option.
But the simplest way to redirect in Nuxt is to use route rules:
export default defineNuxtConfig({
routeRules: {
"/some-url": {
// Temporary redirect using a 307 status code
redirect: "https://nuxt.com/docs/guide/concepts/rendering#route-rules",
},
},
});
It’s pretty straightforward, but route rules don’t give us as much control as some other options.
In this article we’ll cover every single possible way to redirect in Nuxt. We’ll cover:
You can check out the full demo here.
First, we need to make sure we’re on the same page when it comes to why we actually need redirects.
There are a whole lot of reasons to redirect, and your specific use case will determine the type of redirect you need:
Now, let’s get to writing some redirects!
The most important kind of redirect we have available is the server-side redirect.
There are two main ways to do this — server routes or server middleware. We’ll get to those examples shortly, but I need to make a quick detour and explain why server-side redirects are the most powerful.
It is because we get one very important benefit:
Status codes.
Using the right status code during a redirect is crucial to SEO, because it gives the browser/server/web crawler more information about what’s going on, and why the redirect is there in the first place.
We have four main redirect status codes: 301
, 302
, and their newer replacements, 308
and 307
:
301
→ 308
— these are both permanent redirects, but 308
is guaranteed to not have the method or body changed302
→ 307
— these are both temporary redirects, with 307
guaranteed to not have the method or body changed eitherNote: The older status codes were being misused, so new ones were introduced in order to be stricter with their usage. Yes, it’s confusing that the ordering of “permanent” and “temporary” was changed between the two sets, but we’ll just have to live with that (I look them up every time anyway).
The difference between “permanent” and “temporary” is important. The “permanent” redirects will pass along their SEO value (”link juice”) and browsers will cache the assets. The “temporary” redirects won’t do this.
To create a redirect in a Nuxt server route, we can use the sendRedirect
method from h3
:
import { sendRedirect } from 'h3';
export default defineEventHandler((event) =>
// Redirect on the server. Uses a 302 (not 307) by default.
sendRedirect(event, "https://www.jsdocs.io/package/h3#sendRedirect"),
);
You can test it by clicking this link, which will redirect you.
By default, it will use a 302
(temporary redirect) status code. But we can make it use a 307
or any other status code if we prefer:
import { sendRedirect } from 'h3';
export default defineEventHandler((event) =>
// Redirect on the server. Uses a 302 (not 307) by default.
sendRedirect(event, "https://www.jsdocs.io/package/h3#sendRedirect", 307),
);
If we wanted to make a basic link shortener service, we can do that pretty easily. We’ll create this file at server/route/link/[hash].ts
:
import { getRouterParam, sendRedirect } from "h3";
// Mock database
// We would normally get this data from a database somewhere
const db = {
h4sh: "https://www.nuxt.com",
"an0th3r-h4sh": "https://michaelnthiessen.com",
};
export default defineEventHandler((event) => {
const hash = getRouterParam(event, "hash");
const redirectUrl = db[hash];
return sendRedirect(event, redirectUrl, 307);
});
We’ll set up a mock database for simplicity, and then look up the correct URL to redirect to based on the hash
parameter in the route.
You can test out the URL shortener with these two links:
Creating redirects in server middleware works exactly the same as with server routes — we’re still in the Nitro and h3 server. The main difference is that server middleware are run on every request we get, so they’re effectively global. This means we just need to be more careful with our business logic.
We’ll create a file in server/middleware/redirect.ts
:
import { getRequestURL, sendRedirect } from "h3";
export default defineEventHandler((event) => {
const url = getRequestURL(event);
// Always redirect on the server-side
if (url.pathname === "/server-middleware") {
return sendRedirect(event, "https://michaelnthiessen.com");
}
});
Whenever we try to go to /server-middleware
, the middleware will intercept that request and redirect us to my website instead.
Try it out by using this link.
The actual route handler for /server-middleware
won’t get executed, but it does need to exist or the router will give us an error. You can test this by deleting the /server-middleware
page in the demo.
Doing things on the server-side also allows you to create powerful proxies with h3
. There are several built-in methods to help you do this, or you can use the h3 proxy library which builds on those methods to make things simpler for you.
One of the best parts of Nuxt is that it gives us universal rendering — it combines the best of both server-side rendering and client-side rendering.
We can get those same benefits when doing redirects using route middleware and route rules.
This is one of the best ways to encapsulate more complex redirection logic, since it will run on both the server and client. And, because it runs inside the router, it can intercept routes that don’t exist without throwing errors (unlike server routes/middleware).
We’ll create our middleware at middleware/redirect.global.ts
:
export default defineNuxtRouteMiddleware((to, from) => {
if (to.path.startsWith("/middleware")) {
return navigateTo("/another-page");
}
});
This is set to be a global
middleware, but you can set this up however you want — as named, global, or inline middleware. If we try to go to /middleware
, this route middleware will intercept and navigate us to /another-page
instead.
You can test this using this link.
By default, navigateTo
will use a 302
redirect code (temporary redirect). We can change this status code by using the redirectCode
property in the options object:
export default defineNuxtRouteMiddleware((to, from) => {
if (to.path.startsWith("/middleware")) {
return navigateTo("/another-page", {
redirectCode: 307
});
}
});
If we want to redirect to an external page, we’ll need to set external
to true
, because it won’t allow us to do this by default:
export default defineNuxtRouteMiddleware((to, from) => {
if (to.path.startsWith("/middleware")) {
return navigateTo("/another-page", {
redirectCode: 307
});
} else if (to.path.startsWith("/external-middleware")) {
return navigateTo(
"https://nuxt.com/docs/api/utils/navigate-to#within-route-middleware",
{
external: true,
},
);
}
});
Here’s the link to test this external redirect.
By far the simplest way to define redirects is by using route rules. The drawback is that you don’t get any ability to add custom logic. But if all you need is a simple redirect it’s the best solution.
And not just for simplicity, either. Route rules will actually configure your host (currently only on Netlify or Vercel) to do the redirects there, before it ever hits your Nitro server. No need to set up a _redirects
file or mess with host specific configuration, since that’s done for you.
Redirects through route rules also work on both server-side and client-side, as of Nuxt 3.8 (which added client-side redirects).
Let’s add a basic redirect by updating our nuxt.config.ts
:
export default defineNuxtConfig({
devtools: { enabled: true },
routeRules: {
"/route-rules": {
// Temporary redirect using a 307 status code
redirect: "https://nuxt.com/docs/guide/concepts/rendering#route-rules",
},
},
});
You can test it using this link.
By default, route rule redirects use the newer 307
temporary status code, but we can supply our own:
export default defineNuxtConfig({
devtools: { enabled: true },
routeRules: {
"/route-rules": {
// Temporary redirect using a 307 status code
redirect: "https://nuxt.com/docs/guide/concepts/rendering#route-rules",
},
"/route-rules-permanent": {
// Redirect permanently using a 308 code
redirect: {
to: "https://nitro.unjs.io/config#routerules",
statusCode: 308,
},
},
},
});
You can see this in action by looking at index.vue
in the demo and seeing how NuxtLink
is used for the various redirects.
Of course, we can also do purely client-side redirects if we have a specific UX reason for doing so. Although, generally, we don’t want to do this because we aren’t able to provide any status codes.
But redirect status codes aren’t always needed!
Every once in awhile we need to do an on-page redirect. We can do that using navigateTo
, just like with our route middleware:
<template>
This page will redirect automatically in {{ timeLeft }}s
</template>
<script setup>
const timeLeft = ref(5);
onMounted(() => {
setInterval(async () => {
if (timeLeft.value === 1) {
await navigateTo("https://michaelnthiessen.com", {
// Redirecting to external URLs is not allowed by default
external: true,
});
}
timeLeft.value = timeLeft.value - 1;
}, 1000);
});
</script>
Once the countdown reaches one second left, it will perform a redirect using navigateTo
with external
set to true
so we can go to an external URL. Not something you’ll use often, but nice to have it in your back pocket!
Check out the client-side redirect here.
There are a lot of ways to redirect in Nuxt.
Just keep in mind — do you need the proper status codes, and how much flexibility do you need? That will determine which method you use.
Here’s a link to the demo again in case you missed it.
If you want to learn more about Nuxt, the best way to do that is through Mastering Nuxt, the official course that I created in partnership with VueSchool and NuxtLabs. You’ll learn to build a full-stack, real-world app, learning all the most important features of Nuxt along the way.