• Fri, Mar 2026

Vue Router Tutorial: Creating Single Page Applications (SPA)

Vue Router Tutorial: Creating Single Page Applications (SPA)

This in-depth tutorial teaches you how to use Vue Router to build Single Page Applications (SPAs) with Vue.js.It includes practical examples and actionable steps to help you master Vue Router like a pro.

Introduction

If you’ve ever browsed a modern web app and marveled at how pages load instantly without that awkward “white flash,” then congratulations—you’ve already experienced the magic of a Single Page Application (SPA). And if you’re working with Vue.js, the secret sauce behind that magic is none other than Vue Router.

I still remember my first time tinkering with Vue Router. I was coming from a background of traditional multi-page PHP apps where every click felt like a mini-vacation for my server. Vue Router was like strapping a turbocharger to my project—it was smooth, instant, and made me feel like I was finally building apps that belonged in 2025 rather than 2005.

What is Vue Router?

Vue Router is the official routing library for Vue.js. It enables navigation between different components while keeping your app a single page. That means instead of hitting the server for every new page, the app dynamically swaps components based on the route.

Why Use Vue Router?

  • Build SPAs with smooth transitions.
  • Handle dynamic URLs easily (e.g., /user/1).
  • Enable navigation guards for authentication.
  • Support for history mode and hash mode.

Step 1: Setting Up Vue and Vue Router

First things first, you’ll need a Vue project. If you don’t have one yet, create it with Vite:

npm create vite@latest vue-router-tutorial
cd vue-router-tutorial
npm install

Now install Vue Router:

npm install vue-router@4

Yes, version 4—because Vue 3 works best with Vue Router 4.

Step 2: Basic Router Setup

Create a folder for your pages:

mkdir src/pages

Add two simple Vue components for testing:

// src/pages/Home.vue
<template>
  <div>
    <h1>Home Page</h1>
    <p>Welcome to our Vue Router Tutorial SPA.</p>
  </div>
</template>
// src/pages/About.vue
<template>
  <div>
    <h1>About Page</h1>
    <p>This is the about section of our SPA.</p>
  </div>
</template>

Now create the router configuration file:

// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../pages/Home.vue';
import About from '../pages/About.vue';

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About }
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

Next, plug it into main.js:

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

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

Now add the <router-view> and <router-link> inside App.vue:

<template>
  <nav>
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
  </nav>
  <router-view />
</template>

Run the dev server:

npm run dev

Congratulations, you just created your first Vue Router-powered SPA.

Step 3: Dynamic Routes

Dynamic routes let you render different content based on parameters. Perfect for things like user profiles.

// src/pages/User.vue
<template>
  <div>
    <h1>User Page</h1>
    <p>User ID: {{ $route.params.id }}</p>
  </div>
</template>
// router/index.js
import User from '../pages/User.vue';

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  { path: '/user/:id', component: User }
];

Now visiting /user/42 will show “User ID: 42”. Magic!

Step 4: Nested Routes

Sometimes you need a parent-child view structure. That’s where nested routes come in handy.

// src/pages/Dashboard.vue
<template>
  <div>
    <h1>Dashboard</h1>
    <router-view />
  </div>
</template>
// src/pages/DashboardHome.vue
<template>
  <p>Welcome to your dashboard home.</p>
</template>
// src/pages/DashboardSettings.vue
<template>
  <p>Here you can adjust your settings.</p>
</template>
// router/index.js
import Dashboard from '../pages/Dashboard.vue';
import DashboardHome from '../pages/DashboardHome.vue';
import DashboardSettings from '../pages/DashboardSettings.vue';

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  {
    path: '/dashboard',
    component: Dashboard,
    children: [
      { path: '', component: DashboardHome },
      { path: 'settings', component: DashboardSettings }
    ]
  }
];

Now /dashboard shows the dashboard home and /dashboard/settings shows the settings.

Step 5: Navigation Guards

Security is crucial. Navigation guards help you protect routes.

// router/index.js
router.beforeEach((to, from, next) => {
  const isAuthenticated = false; // mock authentication
  if (to.path.startsWith('/dashboard') && !isAuthenticated) {
    next('/');
  } else {
    next();
  }
});

Now try visiting /dashboard. Without authentication, you’ll be redirected to /.

Step 6: Programmatic Navigation

Sometimes you don’t want links—you want to navigate programmatically.

<script setup>
import { useRouter } from 'vue-router';
const router = useRouter();

function goToAbout() {
  router.push('/about');
}
</script>

<template>
  <button @click="goToAbout">Go to About</button>
</template>

Click the button, and boom—you’re on the About page.

Step 7: History Mode vs Hash Mode

Vue Router supports two modes:

  • Hash Mode: URLs look like /#/about. Works everywhere.
  • History Mode: Cleaner URLs like /about. Requires server configuration.

Our example already uses history mode: createWebHistory(). If you prefer hash mode, just switch to createWebHashHistory().

Step 8: Lazy Loading Routes

For performance, you can lazy-load components.

const routes = [
  { path: '/', component: () => import('../pages/Home.vue') },
  { path: '/about', component: () => import('../pages/About.vue') }
];

This ensures components are only loaded when needed.

Step 9: Scroll Behavior

By default, navigating doesn’t reset scroll position. Let’s fix that:

const router = createRouter({
  history: createWebHistory(),
  routes,
  scrollBehavior() {
    return { top: 0 };
  }
});

Now every route change scrolls to the top. Much better!

Step 10: Putting It All Together

At this point, you’ve got everything you need for a robust SPA:

  • Basic and dynamic routes
  • Nested routes for dashboards
  • Navigation guards for security
  • Programmatic navigation
  • Lazy loading and scroll behavior

Conclusion

Vue Router transforms Vue.js from a simple component library into a full-fledged SPA framework. With the power of routes, guards, and dynamic rendering, you can create applications that feel fast, seamless, and modern.

And honestly, once you get used to this, going back to “traditional page reloads” feels like dialing into the internet with a 90s modem. Vue Router is that powerful—it makes your apps not just functional, but delightful.

Now go ahead and build your next SPA with confidence. You’ve got all the tools and knowledge to make it happen!

This website uses cookies to enhance your browsing experience. By continuing to use this site, you consent to the use of cookies. Please review our Privacy Policy for more information on how we handle your data. Cookie Policy