How to Redirect in Nuxt (Every Single Way)

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.

Michael Thiessen
Nuxt 3

Mastering Nuxt 3 course is here!

Get notified when we release new tutorials, lessons, and other expert Nuxt content.

Click here to view the Nuxt 3 course

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:

  • Why we need redirects in the first place
  • Server-side redirects
    • With server routes
    • With server middleware
  • Universal redirects
    • With route middleware
    • With route rules
  • Client-side redirects
    • Inside your Vue components

You can check out the full demo here.

Why Redirects?

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:

  • User Experience — ****Redirects ensure users are directed to the correct or updated page, maintaining a smooth browsing experience without encountering broken links.
  • SEO Benefits — Proper redirects help preserve search engine rankings by transferring the SEO value from old URLs to new ones, preventing the loss of traffic and link equity.
  • Auth — Redirects are often used during authentication to make sure a user cannot access a restricted endpoint.
  • Site Maintenance — During site restructuring, redesigns, or migrations, redirects help manage changes in URL structure, ensuring that users and search engines can still find the relevant content.
  • Domain Changes — When changing domain names, redirects ensure that all traffic from the old domain is seamlessly transferred to the new domain.
  • A/B Testing — Redirects can be used to send portions of traffic to different versions of a page for testing purposes, helping in optimizing content and user experience.
  • Canonicalization — Redirects help in consolidating different URLs that point to the same content, preventing duplicate content issues and ensuring consistency.

Now, let’s get to writing some redirects!

Server-side 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:

  • 301308 — these are both permanent redirects, but 308 is guaranteed to not have the method or body changed
  • 302307 — these are both temporary redirects, with 307 guaranteed to not have the method or body changed either

Note: 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.

Server Routes

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:

Server Middleware

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.

Proxies

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.

Universal redirects

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.

Route Middleware

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.

Route Rules

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.

Client-side 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.

Conclusion

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.

Michael Thiessen
Michael is a passionate full time Vue.js and Nuxt.js educator. His weekly newsletter is sent to over 11,000 Vue developers, and he has written over a hundred articles for his blog and VueSchool.

Follow MasteringNuxt on