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 } })

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)
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')
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.

Related essays

Next essay
Vue.js Best Practices and Patterns