Vue Router is the official routing library for Vue SPAs. It maps URLs to components without full page reloads.

Installation

  npm install vue-router@4
  

Basic Setup

src/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 },
  { path: '/:pathMatch(.*)*', name: 'not-found', component: () => import('../views/NotFound.vue') },
];

export default createRouter({
  history: createWebHistory(),
  routes,
});
  

Register in main.js:

  import { createApp } from 'vue';
import App from './App.vue';
import router from './router';

createApp(App).use(router).mount('#app');
  

App Layout with RouterView

src/App.vue:

  <script setup>
import { RouterLink, RouterView } from 'vue-router';
</script>

<template>
  <nav>
    <RouterLink to="/">Home</RouterLink>
    <RouterLink to="/about">About</RouterLink>
  </nav>
  <RouterView />
</template>
  

Route Parameters

  { path: '/users/:id', name: 'user', component: UserProfile }
  
  <!-- views/UserProfile.vue -->
<script setup>
import { ref, watch } from 'vue';
import { useRoute } from 'vue-router';

const route = useRoute();
const user = ref(null);

watch(
  () => route.params.id,
  async (id) => {
    const res = await fetch(`/api/users/${id}`);
    user.value = await res.json();
  },
  { immediate: true }
);
</script>

<template>
  <h1 v-if="user">{{ user.name }}</h1>
  <p v-else>Loading...</p>
</template>
  

Programmatic Navigation

  <script setup>
import { useRouter } from 'vue-router';

const router = useRouter();

function goToDashboard() {
  router.push('/dashboard');
}
</script>
  

Protect routes with a beforeEach guard:

  router.beforeEach((to, from, next) => {
  const isLoggedIn = localStorage.getItem('token');

  if (to.meta.requiresAuth && !isLoggedIn) {
    next({ name: 'login' });
  } else {
    next();
  }
});
  
  { path: '/dashboard', component: Dashboard, meta: { requiresAuth: true } }
  

Lazy Loading

Use dynamic imports for code splitting:

  {
  path: '/admin',
  component: () => import('../views/Admin.vue'),
}
  

Vue Router is the standard for Vue SPAs — pair it with Pinia for shared application state.