Chapter 37: Vue Routing
Vue Routing (Vue Router), one of the most important parts of building any real Vue application that has more than one page.
In February 2026, almost every Vue 3 project that is more than a single-page prototype uses Vue Router (official routing library). Without routing, your app is just one giant component — with routing, it becomes a proper multi-page Single Page Application (SPA) with clean URLs, back/forward button support, deep linking, lazy loading, authentication guards, nested views, etc.
Let’s go through it step by step like a proper classroom session — no rushing, lots of real examples.
1. What is Vue Routing? (Simple Human Explanation)
Imagine your app is a house with many rooms:
- Home page (landing / dashboard)
- Profile page
- Settings page
- Products list
- Product detail (dynamic URL)
- Login page
- 404 Not Found page
Vue Router is the smart doorman + map of the house:
- When user types /profile or clicks a link → router opens the correct room (component)
- When user clicks browser back button → router takes them to the previous room
- When you want to go programmatically (after login) → router says router.push(‘/dashboard’)
- When you want a URL that changes without full page reload → that’s SPA magic (no <a href> reloads)
Vue Router handles all this declaratively — you define routes (path → component mapping), and Vue takes care of the rest.
2. Current Standard in 2026: Vue Router 4 + Vite
Vue Router 4 is the version used with Vue 3. Installation (if you didn’t choose router during npm create vite):
|
0 1 2 3 4 5 6 |
npm install vue-router@4 |
3. Step-by-Step Setup (Modern 2026 Way)
1. Create router file src/router/index.ts
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
// src/router/index.ts import { createRouter, createWebHistory } from 'vue-router' // Lazy-loaded components (recommended for performance) const HomeView = () => import('@/views/HomeView.vue') const AboutView = () => import('@/views/AboutView.vue') const ProfileView = () => import('@/views/ProfileView.vue') const NotFound = () => import('@/views/NotFound.vue') const router = createRouter({ // Use HTML5 history mode (clean URLs: /profile, not /#/profile) history: createWebHistory(import.meta.env.BASE_URL), // Routes array – most important part routes: [ { path: '/', name: 'home', component: HomeView, meta: { requiresAuth: false } // optional metadata }, { path: '/about', name: 'about', component: AboutView }, { path: '/profile', name: 'profile', component: ProfileView, meta: { requiresAuth: true } // we'll use this later for guards }, // Catch-all route for 404 { path: '/:pathMatch(.*)*', name: 'not-found', component: NotFound } ] }) // Optional: Global navigation guards (very common) router.beforeEach((to, from, next) => { const isLoggedIn = !!localStorage.getItem('token') if (to.meta.requiresAuth && !isLoggedIn) { next({ name: 'login', query: { redirect: to.fullPath } }) } else { next() } }) export default router |
2. Connect router to app src/main.ts
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
import { createApp } from 'vue' import App from './App.vue' import router from './router' // ← import here const app = createApp(App) app.use(router) // ← tell Vue to use router app.mount('#app') |
3. Make App.vue just a wrapper with <router-view>
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!-- src/App.vue --> <template> <!-- This is where routed pages appear --> <router-view /> </template> <script setup lang="ts"> // Usually empty or has global layout </script> |
4. Navigation – How Users Move Between Pages
A. Using <router-link> (preferred – declarative)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<!-- Inside any component --> <router-link to="/">Home</router-link> <router-link to="/about">About</router-link> <!-- Named route + params --> <router-link :to="{ name: 'profile', params: { id: 123 } }"> Go to Profile #123 </router-link> <!-- With query params --> <router-link :to="{ name: 'search', query: { q: 'vue router' } }"> Search </router-link> |
B. Programmatic navigation (in JavaScript)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<script setup> import { useRouter } from 'vue-router' const router = useRouter() function goToProfile() { router.push({ name: 'profile', params: { id: 123 } }) // or router.push('/profile/123') } function goBack() { router.back() } async function loginAndRedirect() { // fake login localStorage.setItem('token', 'xyz') await router.push('/dashboard') } </script> |
5. Dynamic Routes (Params)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
// in router/index.ts { path: '/profile/:id(\\d+)', name: 'profile', component: () => import('@/views/ProfileView.vue'), props: true // auto-pass :id as prop "id" } |
In ProfileView.vue
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
<script setup lang="ts"> defineProps<{ id: string // comes from URL :id }>() console.log('User ID from URL:', id) </script> |
6. Nested Routes (Very Common in Real Apps)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ path: '/dashboard', component: () => import('@/layouts/DashboardLayout.vue'), children: [ { path: '', component: DashboardHome }, { path: 'settings', component: DashboardSettings }, { path: 'profile', component: DashboardProfile } ] } |
DashboardLayout.vue (parent with <router-view>)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
<template> <div class="dashboard-layout"> <aside>Sidebar</aside> <main> <router-view /> <!-- nested routes appear here --> </main> </div> </template> |
Quick Summary Table – Vue Router Essentials (2026)
| Feature | Syntax / Pattern | Why / When to use it |
|---|---|---|
| Basic route | { path: ‘/about’, component: AboutView } | Static pages |
| Named route | name: ‘profile’ → router.push({ name: ‘profile’ }) | Refactor-safe links |
| Dynamic param | path: ‘/user/:id’ → :to=”{ params: { id: 123 } }” | Detail pages |
| Nested routes | children: [ … ] + <router-view> in parent | Layouts with sidebar |
| Lazy loading | component: () => import(‘@/views/Profile.vue’) | Faster initial load |
| Navigation guard | router.beforeEach((to, from) => { … }) | Auth, analytics |
| Query params | ?search=vue → to.query.search | Filters, pagination |
| 404 page | { path: ‘/:pathMatch(.*)*’, component: NotFound } | Catch-all |
Your First Mini Project After This Lesson
- Create HomeView.vue, AboutView.vue, ProfileView.vue
- Set up router with 3 routes + 404
- Add <router-link> navigation bar in App.vue
- Add a simple auth guard (fake login button → redirect to /profile)
Any part confusing? Want to see:
- Full auth flow with login redirect & protected routes?
- Nested routes with sidebar layout?
- Route meta + navigation guards with Pinia?
- Query params + pagination example?
- Programmatic navigation after form submit?
Just tell me — we’ll build the next real routing example together 🚀
Happy routing from Hyderabad! 💙
