menu

Creating Redirects With Nuxt

Redirects are like Thanos, they are INEVITABLE. In this post we'll explore different ways of making redirects in your Nuxt application.

Why You Should Care About Redirects

  • SEO: Redirects are very important when transferring link equity from 1 website to another if a given url changes from the old site to the new.
  • Backlinks: If your site has been around for a while, hopefully people have pointed links 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 have a chance to return a proper HTTP status code. When running Nuxt in universal mode, you can use serverMiddleware or middleware.

serverMiddleware

As the name implies, serverMiddleware is ran only on the server and only available if you run Nuxt in universal mode. 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 unclutter your client-side experience and keep it performant. In general, only use middleware if you have no other choice.

To use serverMiddleware just create a file (no specific directory) and link to it in your nuxt.config.js. Below, we are telling Nuxt we'd like to run this serverMiddleware for all paths so we have 1 central spot for redirects. Of course, you can do whatever you want.

nuxt.config.js
module.exports = {
  mode: 'universal',
  serverMiddleware: [
    {
      path: '/',
      handler: './myServerMiddleware',
    },
  ],
}

Using The Nuxt Default Server

If you use Nuxt's default server you have to do a bunch of url parsing and redirecting yourself. This template uses a library called url-parse which makes chopping relative urls easy (since Node's native URL lib doesn't support them).

Default Middleware Template
import Url from 'url-parse'

export default (req, res, next) => {
  const url = new Url(req.url)
  // 1) detect urls you'd like to redirect
  // 2) call the local redirect helper
  // 3) return if it's a match, don't run next()!
  next()
}

function redirect(res, location) {
  res.writeHead(301, {
    location,
  })
  res.end()
}

Using Express

If you use Express (which is no longer an option in the Nuxt CLI), creating redirects is easy because Express exposes request properties and methods that do all of the hard work for you.

Express Middleware Template
export default (req, res, next) => {
  // 1) detect urls you'd like to redirect
  // 2) call res.redirect(CODE, NEWURL)
  // 3) return if it's a match, don't run next()!
  next()
}

Following this general pattern, here are some handy redirect rules.

Redirect This One Url

// using the default server
if (url.pathname == '/oldpage1/') {
  redirect(res, '/page1/')
  return
}

// using express
if (req.path == '/oldpage1/') {
  res.redirect(301, '/page1/')
  return
}

All Urls Are Lowercase

// using the default server
if (url.pathname.match(/[A-Z]/)) {
  url.set('pathname', url.pathname.toLowerCase())
  redirect(res, url.href)
  return
}

// using express
if (req.path.match(/[A-Z]/)) {
  const newPath = req.path.toLowerCase()
  res.redirect(301, req.originalUrl.replace(req.path, newPath))
  return
}

All Paths End In Slash

// using the default server
if (url.pathname.indexOf('.') == -1 && !url.pathname.endsWith('/')) {
  url.set('pathname', url.pathname + '/')
  redirect(res, url.href)
  return
}

// using express
if (req.path.indexOf('.') == -1 && !req.path.endsWith('/')) {
  const newPath = req.path + '/'
  res.redirect(301, req.originalUrl.replace(req.path, newPath))
  return
}

Map All Urls From The Old Domain To New

// using the default server
if (req.headers.host == 'www.old-site.net') {
  redirect(req, 'http://newsite.com' + req.href)
  return
}

// using express
if (req.hostname == 'www.old-site.net') {
  res.redirect(301, 'http://newsite.com' + req.originalUrl)
  return
}

All Urls Use SSL

If you'd like to redirect HTTP to HTTPS, Nuxt has a very simple serverMiddleware lib that you can use called redirect-ssl. Just include the lib in your package.json file and add it to your serverMiddleware section in your nuxt.config.js file.

nuxt.config.js
module.exports = {
  mode: 'universal',
  serverMiddleware: ['redirect-ssl']
}

Import Redirects

If you wanted something a little more robust you could just toss all of your redirects into 1 file and import them.

myServerMiddleware.js
import rules from './redirects'

export default (req, res, next) => {
  if (rules[req.path]) {
    const rule = rules[req.path]
    res.redirect(rule.code, rule.dst)
    return
  }

  next()
}
redirects.js
export default {
  '/oldpage3/': {
    dst: '/page3/',
    code: 302
  }
}

If you have a lot of redirects it may be easier to use a CSV or TSV and read them in when Nuxt spins up.

Import From An API

It's outside the scope of this post, but you could even load redirects in from an API when Nuxt spins up! Then you could load them into cache using memory-cache and refresh them every couple of minutes.

Nuxt Community redirect-module

If this all seems a bit overwhelming, no problem! The Nuxt Core Team has created a module to help with the burden of doing all of this yourself.

It automatically injects serverMiddleware into your app and lets you control your redirect rules right in your nuxt.config.js file. It even supports async api calls and is powered by regular expressions! It's definitely worth checking out.

Middleware

The second way to enforce redirects is through middleware. Here things get a little tricky as it's ran both server-side and client-side. Middleware is located in the /middleware/ directory.

You can make middleware run on every route.

nuxt.config.js
export default {
  router: {
    // ran before every route on both client and server
    middleware: ['myMiddleware'],
  },
}

Or for all pages under this layout.

/layouts/default.vue
export default {
  middleware: ['myMiddleware'],
}

Or for this page.

/pages/index.vue
export default {
  middleware: ['myMiddleware'],
}

Your middleware takes a context object and can even return a promise! The context object has many properties, two of which are route and redirect. On server-side, the redirect function is the exact same one as we called above in serverMiddleware.

/middleware/myMiddleware.js
export default function (ctx) {
  if (ctx.route.fullPath == '/oldpage4/') ctx.redirect(301, '/page4')
}

If you are redirecting client-side, then this is just done via javascript and no HTTP status codes are used.

Keep in mind, the context object contains a req property that's just like the one used in serverMiddleware but it's not available client-side! To protect yourself you'll need to wrap any code that uses it inside middleware with if (process.server)

True HTTP Status Codes When Using Nuxt Generate

It's common to use Nuxt to create super fast JAMStack sites. In these cases serverMiddleware isn't available since you are running generate. If you want server-side redirects with real HTTP status codes you have to use whatever methods your hoster has. Here are the methods for Netlify and Zeit

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.