LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 3216 min read

Dynamic Routes & Navigation Guards

Build routes with parameters and protect routes from unauthorized access using navigation guards.

Dynamic Route Parameters

A colon-prefixed segment in a route's path becomes a dynamic parameter, matching any value in that position.

const routes = [
{ path: '/products/:id', component: ProductPage },
];
// /products/42 → route.params.id === '42'

Reading Route Params

The useRoute composable gives you reactive access to the current route, including its params.

<script setup>
import { useRoute } from 'vue-router';
import { ref, watchEffect } from 'vue';
const route = useRoute();
const product = ref(null);
watchEffect(async () => {
product.value = await fetchProduct(route.params.id);
});
</script>
<template>
<h1 v-if="product">{{ product.name }}</h1>
</template>
Why watchEffect Here

Because Vue Router can reuse the same component instance when navigating between /products/1 and /products/2, watchEffect re-running whenever route.params.id changes is what re-fetches the data — a plain onMounted alone would miss subsequent param changes.

Nested Routes

A route can define children, rendered through a nested <RouterView> inside the parent route's own component — directly mirroring nested layouts in other frameworks.

const routes = [
{
path: '/dashboard',
component: DashboardLayout,
children: [
{ path: '', component: DashboardHome },
{ path: 'settings', component: DashboardSettings }, // → /dashboard/settings
],
},
];

A navigation guard runs before a route change completes, and can allow it, redirect elsewhere, or cancel it — the standard tool for authentication checks.

router.beforeEach((to, from) => {
const isLoggedIn = Boolean(localStorage.getItem('token'));
if (to.meta.requiresAuth && !isLoggedIn) {
return '/login'; // redirect
}
});
const routes = [
{ path: '/dashboard', component: DashboardPage, meta: { requiresAuth: true } },
];

Common Beginner Mistakes

Treating route.params values as numbers

Route params are always strings — convert them explicitly (Number(route.params.id)) before using them in numeric comparisons.

Doing full server-side auth verification inside a navigation guard

Guards run entirely on the client — treat them as a UX-level redirect, and always enforce real authorization on your actual backend/API.

FAQs

It's a free-form object you attach custom data to per route — like requiresAuth above — readable in guards and components alike.

Yes — beforeRouteEnter, beforeRouteUpdate, and beforeRouteLeave are per-component guards, alongside the global beforeEach shown here.

Summary

Dynamic params make routes data-driven, and navigation guards gate access before a route change completes. Next, you'll move from routing into state management with Pinia.

Next Lesson →

State Management with Pinia