Next.js starter your AI actually understands. Ship internal tools in days not weeks. Pre-order $199 $499 → [Get it now]

How to use Vue Router guards

Vue Router guards enable control over navigation flow with hooks that run before, during, and after route transitions. As the creator of CoreUI with 12 years of Vue development experience, I’ve implemented router guards in production Vue applications that protect authenticated routes and manage complex navigation logic for millions of users.

The most secure approach combines global guards for authentication with per-route guards for role-based access control.

Global Before Guards

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', component: Home },
    { path: '/login', component: Login },
    { path: '/dashboard', component: Dashboard, meta: { requiresAuth: true } },
    { path: '/admin', component: Admin, meta: { requiresAuth: true, role: 'admin' } }
  ]
})

router.beforeEach((to, from, next) => {
  const isAuthenticated = localStorage.getItem('authToken')
  const userRole = localStorage.getItem('userRole')

  if (to.meta.requiresAuth && !isAuthenticated) {
    next('/login')
  } else if (to.meta.role && userRole !== to.meta.role) {
    next('/')
  } else {
    next()
  }
})

export default router

Per-Route Guards

const routes = [
  {
    path: '/profile',
    component: Profile,
    beforeEnter: (to, from, next) => {
      if (isUserLoggedIn()) {
        next()
      } else {
        next('/login')
      }
    }
  },
  {
    path: '/admin',
    component: Admin,
    beforeEnter: (to, from, next) => {
      if (hasAdminAccess()) {
        next()
      } else {
        next({ name: 'Forbidden' })
      }
    }
  }
]

Component Guards

<script>
export default {
  name: 'EditPost',

  beforeRouteEnter(to, from, next) {
    fetchPost(to.params.id).then(post => {
      next(vm => {
        vm.post = post
      })
    })
  },

  beforeRouteUpdate(to, from, next) {
    this.post = null
    fetchPost(to.params.id).then(post => {
      this.post = post
      next()
    })
  },

  beforeRouteLeave(to, from, next) {
    if (this.hasUnsavedChanges) {
      const answer = window.confirm('You have unsaved changes. Leave anyway?')
      next(answer)
    } else {
      next()
    }
  }
}
</script>

Async Authentication Guard

import { useAuthStore } from '@/stores/auth'

router.beforeEach(async (to, from, next) => {
  const authStore = useAuthStore()

  if (to.meta.requiresAuth) {
    if (!authStore.isAuthenticated) {
      try {
        await authStore.checkAuth()
        next()
      } catch (error) {
        next({
          path: '/login',
          query: { redirect: to.fullPath }
        })
      }
    } else {
      next()
    }
  } else {
    next()
  }
})

Composition API Guards

<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
import { ref } from 'vue'

const hasUnsavedChanges = ref(false)

onBeforeRouteLeave((to, from, next) => {
  if (hasUnsavedChanges.value) {
    const answer = window.confirm('Discard unsaved changes?')
    next(answer)
  } else {
    next()
  }
})

onBeforeRouteUpdate(async (to, from, next) => {
  if (to.params.id !== from.params.id) {
    await loadData(to.params.id)
  }
  next()
})
</script>

Global After Hooks

router.afterEach((to, from) => {
  // Update page title
  document.title = to.meta.title || 'My App'

  // Track page view
  if (window.gtag) {
    window.gtag('config', 'GA_MEASUREMENT_ID', {
      page_path: to.fullPath
    })
  }

  // Scroll to top
  window.scrollTo(0, 0)
})

Best Practice Note

This is the same navigation guard architecture we use in CoreUI’s Vue admin templates. Guards provide centralized control over route access and navigation flow. Always handle async operations properly in guards, use route meta fields for configuration, and implement proper error handling for failed navigations. Store sensitive auth checks server-side and use guards only for UI/UX improvements.

For production applications, consider using CoreUI’s Vue Admin Template which includes pre-configured router guards with authentication and role-based access control.

For complete routing implementation, check out how to use Vue Router and how to handle authentication in Vue.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.
How to loop through a 2D array in JavaScript
How to loop through a 2D array in JavaScript

How to dynamically add, remove, and toggle CSS classes in React.js
How to dynamically add, remove, and toggle CSS classes in React.js

How to change opacity on hover in CSS
How to change opacity on hover in CSS

How to Add a Tab in HTML
How to Add a Tab in HTML

Answers by CoreUI Core Team