How to use Global Navigation Guards with Nuxt Middleware, and why you absolutely should NOT
Tags: nuxt, vue, beginners, bug
Published: 2019-08-09 10:40:26

---
title: How to use Global Navigation Guards with Nuxt Middleware, and why you absolutely should NOT
published: true
description: Yes, you can use Global Navigation Guards with Nuxt Middleware.  No, you should not be doing that. A beginner in Vue/Nuxt explains the problem he faced, and how he solved it.
tags: nuxt, vue, beginner, bug
---

TLDR:
- It's possible to use Global Navigation Guards with Nuxt by using Middleware
- In the Middleware, you have access to the context, by which you can directly access the Vue Router.
- By adding a Global Navigation Guard, that code will run every time your router is used, leading to unintended consequences
- Instead, use in-component Navigation Guards within your pages

I'm still very new to Vue and Nuxt, but as we are using it at my job I'm trying to pick it up as I go.  We are building a task management system similar to Pivotal Tracker or Trello.  We have Lists, and within these Lists we have Tasks, and one Task showing its TaskDetails.  By clicking on the Tasks in the List you can change which TaskDetail is shown. I was faced with what I initially thought was an easy task.

TASK: When a user is editing a text box within the TaskDetail, ensure the user does not accidently navigate away from the page (and losing their edit) by adding a confirm popup.

Enter Navigation Guards ([Navigation Guards | Vue Router](https://router.vuejs.org/guide/advanced/navigation-guards.html)) , which are "primarily used to guard navigations either by redirecting it or canceling it."  By using a Global Navigation Guard, I could ensure that anytime the Vue Router changes the route (when someone clicks on a different Task), I could check if they are editing a text box and then use a confirm popup.

Something like this:
```
const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  if(confirm("Are you sure?")) {
    next()
  } else {
    next(false)
  }
})
```

Problem: We are using Nuxt, which sets up the Vue-router automatically based on your file structure.  But there must be a way to use a Global Navigation Guard with Nuxt, right?

I googled, and all I could find addressing this was [one lone Stack Overflow question](https://stackoverflow.com/questions/53322525/how-to-set-beforeresolve-navigation-guard-in-nuxt-js), which had no answer but at least a useful comment about how middleware was designed for exactly that.

##What is middleware in Nuxt?

"Middleware lets you define custom functions that can be run before rendering either a page or a group of pages." ([Routing - Nuxt.js](https://nuxtjs.org/guide/routing#middleware))  Also importantly, the Middleware has access to the Context ([API: The Context - Nuxt.js](https://nuxtjs.org/api/context)), which has access to the store, which has access to the Vue Router!

So my idea is now simple: create a middleware that accesses the router directly, add a Global Navigation Guard so that whenever the router changes pages it confirms with the user if they really want to move.  Let's do it!

For my middleware I created this basic file
```
in check-before-move.js

export default function ({ store }) {
  store.app.router.beforeEach((to, from, next) => {
    if(confirm("Are you sure?")) {
      next()
    } else {
      next(false)
    }
  })
}
```

Then added that to the config for nuxt
```
in nuxt.config.js

  router: {
    middleware: "check-before-move"
  }
```

This lead to a sticky little problem.  Can you spot it?  If my middleware really does run every time the router runs, what is going to happen?

That's right, every time the router runs I'm adding ANOTHER Global Navigation Guard.  My user has to confirm once, then twice, then three times..etc every time they navigate to different Tasks.  Remember, that middleware file is running from start to finish every time the router moves.  And each time that middleware file runs, we are doing another `beforeEach`.  It's obvious looking at it now, but it took me a long time to figure out at the time!

So my dumb brain said, "Oh ok I just need to add a check to see if I've set it up already", and I immediately changed my code to:
```
in check-before-move.js

export default function ({ store }) {
  let setup = false
  if(!setup) {
    store.app.router.beforeEach((to, from, next) => {
      setup = true
      if(confirm("Are you sure?")) {
        next()
      } else {
        next(false)
      }
    })
  }
}
```

That, as you can imagine, also did not work (read above where I said the code runs from start to finish every time and you'll see why my master plan failed)

So as we can see, YES you can add a Global Navigation Guard in Nuxt by using Middleware, but NO you should not do it(or at least be very sure about what you're doing before implementing it).

##Afterword

For anyone else who may be trying to figure out how to implement the same feature in their own project and is suffering like I did, I'll tell you how I managed to implement a solution.  Instead of going global, I introduced an In-component Guard.  Be careful though, those In-component Guards only work on PAGES, not components (even though Pages are Components but Nuxt has opinions on these matters), so look into In-component Guards here ([Navigation Guards | Vue Router](https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards))

Good luck, and happy coding!

(Note: I am new to Vue/Nuxt as I stated before, so if you spot any mistakes, feel free to point them out!)