Vue Routing
Map URLs to Vue views and navigate without full page reloads.
Overview
Routing decides which component to display for the current URL. Vue Router is Vue's official client-side routing library, enabling Single Page Applications to navigate between views while preserving browser history and updating only the changing application content.
Key concepts
- Routes connect URL paths to components
- RouterLink performs client-side navigation
- RouterView renders the matched view
- Dynamic parameters support reusable detail pages
What is Routing?
Routing maps a URL to a page-level component. When the URL changes, Vue Router selects the matching route and updates the routed portion of the interface.
/ → Home Page
/about → About Page
/contact → Contact Page
/products → Products Page
/products/42 → Product 42Why do we need Routing?
An online learning platform may contain Home, Courses, Tutorials, Blog, and Contact views. Routing gives each view a shareable URL, supports browser back and forward controls, and prevents all content from becoming one long page.
What is Vue Router?
Vue Router synchronizes the URL and displayed component. Internal navigation can occur without requesting a completely new HTML document, producing a smooth Single Page Application experience.
Installing Vue Router
A create-vue project can include Router during setup. Add it later with npm when it is not already installed.
npm install vue-routerCreating Page Components
Route-level components are commonly stored in src/views while smaller reusable UI remains in src/components.
src/
├── components/
├── router/
│ └── index.js
├── views/
│ ├── HomeView.vue
│ ├── AboutView.vue
│ └── ProductView.vue
├── App.vue
└── main.jsCreating Routes
import { createRouter, createWebHistory } from "vue-router";
import HomeView from "../views/HomeView.vue";
import AboutView from "../views/AboutView.vue";
const routes = [
{
path: "/",
name: "home",
component: HomeView
},
{
path: "/about",
name: "about",
component: AboutView
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;Named routes decouple navigation from literal path strings and make future URL changes easier to manage.
Registering the Router
Install the router plugin before mounting the app.
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
createApp(App)
.use(router)
.mount("#app");Creating Navigation Links
RouterLink renders accessible navigation and lets Vue Router handle internal route changes. Normal anchor elements remain appropriate for external websites, downloads, and resources outside the SPA.
<template>
<nav aria-label="Primary navigation">
<RouterLink :to="{ name: 'home' }">Home</RouterLink>
<RouterLink :to="{ name: 'about' }">About</RouterLink>
</nav>
</template>Displaying Routed Pages
RouterView is the outlet where Vue Router renders the component matched by the current URL.
<template>
<SiteHeader />
<main>
<RouterView />
</main>
<SiteFooter />
</template>Dynamic Routes
A dynamic segment begins with a colon and captures part of the URL. One ProductView can display many products.
{
path: "/products/:id",
name: "product",
component: () => import("../views/ProductView.vue"),
props: true
}<RouterLink :to="{ name: 'product', params: { id: product.id } }">
{{ product.name }}
</RouterLink>With props: true, the route parameter is passed to ProductView as a prop, reducing direct coupling to the router.
Reading Route Information
<script setup>
import { useRoute } from "vue-router";
const route = useRoute();
console.log(route.params.id);
</script>Programmatic Navigation
Use useRouter when navigation follows an action such as successful login or form submission.
import { useRouter } from "vue-router";
const router = useRouter();
async function finishCheckout() {
await saveOrder();
router.push({ name: "order-confirmation" });
}Nested Routes
Nested routes render child views inside a parent RouterView, making them useful for dashboards and settings layouts.
{
path: "/account",
component: () => import("../views/AccountView.vue"),
children: [
{ path: "", name: "account", component: AccountOverview },
{ path: "settings", name: "account-settings", component: AccountSettings }
]
}Lazy Loading Routes
Dynamic imports create separate chunks that load only when a route is visited, reducing the initial JavaScript bundle.
{
path: "/reports",
component: () => import("../views/ReportsView.vue")
}Navigation Guards
Guards can redirect users before navigation, for example when a route requires authentication. They improve UX but do not replace server-side authorization.
router.beforeEach((to) => {
if (to.meta.requiresAuth && !authStore.isLoggedIn) {
return {
name: "login",
query: { redirect: to.fullPath }
};
}
});Not Found Route
{
path: "/:pathMatch(.*)*",
name: "not-found",
component: () => import("../views/NotFoundView.vue")
}History Modes and Hosting
| History | URL style | Hosting need |
|---|---|---|
| createWebHistory | /about | Server must fall back to index.html |
| createWebHashHistory | /#/about | Usually no fallback configuration |
Web history produces cleaner URLs but the deployment host must return the SPA entry file for unknown application paths. Otherwise, refreshing a nested route can produce a server 404.
Real-life example
A travel app can map Home, Destinations, Packages, About, and Contact to named routes. A dynamic destination route reuses one view for every location, and navigation feels immediate because only routed content changes.
Common beginner mistakes
- Forgetting app.use(router)
- Omitting RouterView
- Using anchors for internal SPA navigation
- Creating duplicate routes instead of dynamic segments
- Reading a route param once and missing later changes
- Forgetting a not-found route
- Deploying web history without server fallback
- Treating client guards as security authorization
Best practices
- Use meaningful route names
- Keep route configuration organized
- Lazy-load page-level views
- Prefer named navigation for internal links
- Pass params as props when useful
- Provide a not-found experience
- Preserve browser back and forward behavior
- Configure hosting for history mode
- Enforce authorization on the server
Key takeaways
- Routing maps URLs to views
- Vue Router powers client-side Vue navigation
- RouterLink navigates internally
- RouterView renders the matched component
- Dynamic segments reuse detail pages
- Nested routes support layouts
- Lazy loading reduces initial bundles
- Guards control navigation flow
- History mode requires correct hosting configuration