Navigation Guards
Navigation guards are functions Vue Router calls at defined points during a navigation, giving you the chance to inspect, allow, redirect, or cancel it before the new route actually renders. The most common use case is authentication: preventing an unauthenticated user from reaching a protected page by redirecting them to a login screen instead. Guards exist at three scopes — global (registered on the router instance and run on every navigation), per-route (defined in a specific route's beforeEnter option), and in-component (defined inside the target component itself).
Cricket analogy: A stadium's security check inspects every fan's ticket before letting them into the stands — an unauthenticated fan is redirected to the box office instead of the terrace; that check exists at the gate level (global guard), the VIP-box level (per-route beforeEnter), and the individual suite's door (in-component guard).
Global Guards with router.beforeEach
router.beforeEach registers a function that runs before every navigation, receiving the target route (to) and the current route (from). Returning false cancels the navigation; returning a route location redirects; returning nothing or true (or calling next() with no args in the older callback style) allows it to proceed.
Cricket analogy: router.beforeEach is like a match referee checking every substitution request (to) against the current lineup (from) before every over — waving it off cancels the sub, pointing to a different player redirects it, and a nod lets the intended sub proceed.
router.beforeEach((to, from) => {
const isAuthenticated = useAuthStore().isLoggedIn
if (to.meta.requiresAuth && !isAuthenticated) {
return { name: 'login', query: { redirect: to.fullPath } }
}
})Route Meta Fields and Per-Route Guards
Route definitions can carry a meta object with arbitrary custom data, such as requiresAuth: true, which global guards can inspect to decide whether to intervene. For logic scoped to a single route rather than the whole app, beforeEnter can be attached directly to that route's definition instead of writing conditional branches inside a global guard.
Cricket analogy: Tagging a specific innings-review request with meta: { requiresCaptainApproval: true } lets a global umpire check inspect that flag without needing special-case logic for every request type; a specific ground's unique boundary rule can instead live in that ground's own beforeEnter-equivalent local rule.
const routes = [
{
path: '/dashboard',
component: DashboardView,
meta: { requiresAuth: true },
},
{
path: '/admin',
component: AdminView,
beforeEnter: (to, from) => {
if (!useAuthStore().isAdmin) return { name: 'forbidden' }
},
},
]In-component guards like onBeforeRouteLeave are especially useful for 'unsaved changes' confirmation dialogs — prompting the user before they navigate away from a form with unsaved edits, something that's awkward to express as a global or per-route guard since it depends on component-local state.
In the modern (Vue Router 4) API, guards should return a value (false, a route location, or nothing/true) rather than calling a next() callback, though next() is still supported for backward compatibility. Mixing both patterns in the same guard — calling next() and also returning a value — leads to confusing double-resolution and should be avoided.
- Navigation guards intercept routing to allow, cancel, or redirect a navigation before it completes.
- router.beforeEach registers a global guard that runs on every navigation attempt.
- beforeEnter on a route definition scopes guard logic to just that route.
- onBeforeRouteLeave/onBeforeRouteUpdate are in-component guards useful for state tied to the current component.
- Route meta fields (e.g. requiresAuth) let guards make decisions based on route-level configuration.
- Modern guards return false/route-location/nothing rather than calling a next() callback.
Practice what you learned
1. What does router.beforeEach register?
2. What happens if a global guard returns a route location object, e.g. { name: 'login' }?
3. Which guard type is most appropriate for prompting a user about unsaved form changes before leaving a page?
4. What is the purpose of a route's meta field, such as { requiresAuth: true }?
5. Why should you avoid mixing the next() callback with returning a value in the same navigation guard?
Was this page helpful?
You May Also Like
Vue Router Basics
Learn how Vue Router maps URLs to components, enabling single-page applications to feel like multi-page sites without full browser reloads.
Nested Routes
Learn how to compose layouts with parent and child routes so nested UI sections render inside their own router-view outlets.
Dynamic Routes and Route Params
Learn how to define route paths with dynamic segments and read those values reactively inside components using route params.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics