Vue Router Cheat Sheet
Covers Vue Router 4 setup, declarative and programmatic navigation, dynamic and nested routes, navigation guards, and Composition API hooks.
Basic Setup
Create and register the router (Vue 3 / Vue Router 4).
// router/index.jsimport { 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 }, // Lazy-loaded route, code-split into its own chunk { path: '/settings', component: () => import('../views/Settings.vue') },];const router = createRouter({ history: createWebHistory(), routes,});export default router;// main.jsimport { createApp } from 'vue';import App from './App.vue';import router from './router';createApp(App).use(router).mount('#app');
Dynamic & Nested Routes
Route params and layouts with child routes.
const routes = [ { path: '/user/:id', component: User, props: true, // pass route.params as component props }, { path: '/users', component: UsersLayout, children: [ { path: '', component: UserList }, // /users { path: ':id', component: UserDetail }, // /users/123 ], },];
Composition API Hooks
Router access from inside setup().
- useRouter()- Returns the router instance for programmatic navigation (push, replace, back)
- useRoute()- Returns the current reactive route object (params, query, path, meta)
- onBeforeRouteLeave()- Guard called when the current component's route is about to be left
- onBeforeRouteUpdate()- Guard called when the route changes but the same component instance is reused
- router.isReady()- Returns a Promise that resolves once the router finishes its initial navigation
Typed Route Meta & Layout Selection
Augment RouteMeta for type-safe custom fields and drive layout switching from it.
// router/types.d.tsimport 'vue-router';declare module 'vue-router' { interface RouteMeta { requiresAuth?: boolean; roles?: string[]; layout?: 'default' | 'admin' | 'blank'; }}// App.vue// <template>// <component :is=\"layoutFor(route.meta.layout)\">// <router-view />// </component>// </template>// <script setup lang=\"ts\">import { useRoute } from 'vue-router';const route = useRoute();function layoutFor(layout = 'default') { return { default: DefaultLayout, admin: AdminLayout, blank: BlankLayout }[layout];}// </script>
Named Chunks & Route-Level Code Splitting
Group related lazy routes into the same async chunk for fewer network requests.
const routes = [ { path: '/admin', component: () => import(/* webpackChunkName: "admin" */ '../views/AdminHome.vue'), }, { path: '/admin/users', component: () => import(/* webpackChunkName: "admin" */ '../views/AdminUsers.vue'), }, // Vite equivalent: no magic comment needed, Rollup groups by dynamic import graph; // use import.meta.glob for bulk-registering a directory of route components ...Object.entries(import.meta.glob('../views/reports/*.vue')).map(([path, loader]) => ({ path: `/reports/${path.match(/([\w-]+)\.vue$/)[1]}`, component: loader, })),];
scrollBehavior & Route Transitions
Restore scroll position on back/forward and animate route changes.
const router = createRouter({ history: createWebHistory(), routes, scrollBehavior(to, from, savedPosition) { if (savedPosition) return savedPosition; // browser back/forward if (to.hash) return { el: to.hash, behavior: 'smooth' }; return { top: 0 }; },});// App.vue - animate between route components// <router-view v-slot="{ Component, route }">// <transition :name="route.meta.transition || 'fade'" mode="out-in">// <component :is="Component" :key="route.path" />// </transition>// </router-view>
Data Fetching in beforeRouteEnter
Fetch before the component instance exists, then reach it via next(vm => ...).
export default { async beforeRouteEnter(to, from, next) { try { const post = await api.getPost(to.params.id); next(vm => { vm.post = post; }); // vm not available until next() resolves } catch (err) { next('/404'); } }, // For param changes on the *same* component instance, use the Composition API guard instead: // onBeforeRouteUpdate(async (to) => { post.value = await api.getPost(to.params.id); });};
Advanced Router APIs
Lesser-known instance methods and guard-return semantics beyond basic push/replace.
- router.resolve(to)- Resolves a route location object into { href, route, ... } without navigating, useful for building custom links
- router.addRoute() / removeRoute()- Dynamically register or remove routes at runtime, e.g. for plugin-based or role-based route trees
- router.hasRoute(name)- Checks whether a named route currently exists in the routing table
- onError(callback)- Registers a handler for errors thrown inside guards or during lazy-component loading
- beforeResolve- Global guard that fires after all in-component guards and async route components have resolved, right before navigation confirms
- afterEach- Global hook (no next()) for analytics/logging after navigation completes; receives failure as a third argument
- next(false)- Aborts the current navigation and resets the URL bar back to the previous route
Prefer route.meta over hardcoding auth checks in every component — attach meta: { requiresAuth: true } to routes and enforce it once in a global router.beforeEach guard, so new protected routes are secure by default.