Skip to content
All essays
WebMarch 27, 202514 min

Vue Router 4: Complete Guide

Master Vue Router 4 for Vue 3. Learn dynamic routing, nested routes, route guards, and navigation patterns.

Ü
Ümit Uz
Mobile & Full Stack Developer

Vue Router is the official router for Vue.js, enabling you to build single-page applications with multiple views and navigation.

Installation

bash
npm install vue-router@4

Basic Setup

javascript
// router/index.js import { createRouter, createWebHistory } from 'vue-router' import Home from '@/views/Home.vue' import About from '@/views/About.vue' const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/about', name: 'About', component: About } ] const router = createRouter({ history: createWebHistory(), routes }) export default router // main.js import { createApp } from 'vue' import App from './App.vue' import router from './router' const app = createApp(App) app.use(router) app.mount('#app')

Route Configuration

Dynamic Routes

javascript
const routes = [ { path: '/user/:id', name: 'User', component: User, props: true }, { path: '/post/:slug', name: 'Post', component: Post, props: (route) => ({ slug: route.params.slug }) } ]

Nested Routes

javascript
const routes = [ { path: '/user/:id', component: User, children: [ { path: '', component: UserHome }, { path: 'profile', component: UserProfile }, { path: 'posts', component: UserPosts } ] } ]

Named Routes

javascript
const routes = [ { path: '/user/:id', name: 'user', component: User } ] // Navigate using name router.push({ name: 'user', params: { id: 123 } })

Navigation

Programmatic Navigation

javascript
import { useRouter } from 'vue-router' const router = useRouter() // Navigate to path router.push('/home') // Navigate with object router.push({ path: '/home' }) router.push({ name: 'Home' }) // Navigate with params router.push({ name: 'User', params: { id: 123 } }) // Navigate with query router.push({ path: '/search', query: { q: 'vue' } }) // Replace current route router.replace('/home') // Go back/forward router.go(-1) router.go(1)

RouterLink Component

vue
<template> <nav> <RouterLink to="/">Home</RouterLink> <RouterLink :to="{ name: 'About' }">About</RouterLink> <RouterLink :to="`/user/${userId}`">User</RouterLink> <RouterLink :to="{ name: 'User', params: { id: userId } }" :class="{ active: isActive }" > User Profile </RouterLink> </nav> </template>

Route Guards

Global Guards

javascript
// Before each navigation router.beforeEach((to, from, next) => { const isAuthenticated = checkAuth() if (to.meta.requiresAuth && !isAuthenticated) { next('/login') } else { next() } }) // After each navigation router.afterEach((to, from) => { document.title = to.meta.title || 'My App' }) // Before navigation error router.onError((error) => { console.error('Navigation error:', error) })

Per-Route Guards

javascript
const routes = [ { path: '/admin', component: Admin, meta: { requiresAuth: true, role: 'admin' }, beforeEnter: (to, from, next) => { const user = store.state.user if (user.role !== 'admin') { next('/unauthorized') } else { next() } } } ]

In-Component Guards

vue
<script setup> import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router' onBeforeRouteLeave((to, from, next) => { const answer = window.confirm('Do you really want to leave?') if (answer) { next() } else { next(false) } }) onBeforeRouteUpdate((to, from, next) => { // Called when route changes but same component is reused fetchData(to.params.id).then(() => next()) }) </script>

Route Meta Fields

javascript
const routes = [ { path: '/admin', component: Admin, meta: { requiresAuth: true, role: 'admin', title: 'Admin Dashboard' } } ] // Access meta in guards router.beforeEach((to, from, next) => { if (to.meta.requiresAuth && !isAuthenticated()) { next('/login') } else { next() } })

Lazy Loading

javascript
const routes = [ { path: '/about', component: () => import('@/views/About.vue') }, { path: '/admin', component: () => import('@/views/admin/Dashboard.vue') } ]

Router View

vue
<template> <div> <RouterView /> </div> </template> <!-- With named views --> <template> <div> <RouterView name="sidebar" /> <RouterView name="main" /> </div> </template>

Accessing Route Information

vue
<script setup> import { useRoute } from 'vue-router' const route = useRoute() console.log(route.params) console.log(route.query) console.log(route.meta) console.log(route.path) console.log(route.name) </script> <template> <div> <p>Current route: {{ route.path }}</p> <p>Query params: {{ route.query }}</p> </div> </template>

Dynamic Routing

javascript
// Adding routes dynamically router.addRoute({ path: '/new-route', component: NewRoute }) // Adding nested routes router.addRoute('parent', { path: 'new-child', component: NewChild }) // Removing routes router.removeRoute('routeName')

Navigation Guards with Data Fetching

javascript
const routes = [ { path: '/post/:id', component: Post, beforeEnter: async (to, from, next) => { try { const post = await fetchPost(to.params.id) to.params.post = post next() } catch (error) { next('/error') } } } ]

Hash vs History Mode

javascript
// History mode (recommended) const router = createRouter({ history: createWebHistory(), routes }) // Hash mode const router = createRouter({ history: createWebHashHistory(), routes })

404 Page

javascript
const routes = [ // ... other routes { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound } ]

Scroll Behavior

javascript
const router = createRouter({ history: createWebHistory(), routes, scrollBehavior(to, from, savedPosition) { if (savedPosition) { return savedPosition } else { return { top: 0 } } } })

Vue Router 4 provides a flexible and powerful routing solution for Vue 3 applications with excellent TypeScript support and composition API integration.

Next essay
Vue.js Best Practices and Patterns