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