vue-router-skilld
vuejs/router vue-router
Version: 5.0.3 (Feb 2026) Deps: @babel/generator@^7.28.6, @vue-macros/common@^3.1.1, @vue/devtools-api@^8.0.6, ast-walker-scope@^0.8.3, chokidar@^5.0.0, json5@^2.2.3, local-pkg@^1.1.2, magic-string@^0.30.21, mlly@^1.8.0, muggle-string@^0.4.1, pathe@^2.0.3, picomatch@^4.0.3, scule@^1.3.0, tinyglobby@^0.2.15, unplugin@^3.0.0, unplugin-utils@^0.3.1, yaml@^2.8.2 Tags: next: 4.0.13 (Feb 2022), legacy: 3.6.5 (Sep 2022), edge: 4.4.0-alpha.3 (Jun 2024), beta: 5.0.0-beta.2 (Jan 2026), latest: 5.0.3 (Feb 2026)
References: Docs — API reference, guides
API Changes
This section documents version-specific API changes — prioritize recent major/minor releases.
-
NEW:
vue-router/vite— v5 ships the Vite plugin (formerlyunplugin-vue-router/vite) directly in the core package; import fromvue-router/viteinstead source -
NEW:
vue-router/auto-routes— v5 export that provides the auto-generated file-based route list; previously requiredunplugin-vue-routeras a separate package source -
NEW:
vue-router/unplugin— v5 export for Webpack/Rollup/esbuild plugins and utilities (VueRouterAutoImports,EditableTreeNode,createRoutesContext, etc.); previously imported fromunplugin-vue-routersource -
NEW:
DataLoaderPlugin+defineBasicLoader(experimental) — v5 adds data loaders directly tovue-router/experimental; previously inunplugin-vue-router/data-loaders. InstallDataLoaderPluginbefore the router withapp.use(DataLoaderPlugin, { router })source -
NEW:
defineColadaLoader(experimental) — Pinia Colada-backed loader available atvue-router/experimental/pinia-colada; previouslyunplugin-vue-router/data-loaders/pinia-coladasource -
NEW:
NavigationResult(experimental) — class fromvue-router/experimentalreturned inside a loader to redirect during navigation (e.g.return new NavigationResult('/login')); previously did not exist in vue-router source -
NEW: Volar plugins moved to
vue-router/volar/sfc-typed-routerandvue-router/volar/sfc-route-blocks— previouslyunplugin-vue-router/volar/sfc-typed-routerandunplugin-vue-router/volar/sfc-route-blockssource -
NEW:
TypesConfigmodule augmentation — v4.4+ interface used to registerRouteNamedMapfor typed routes; augment withdeclare module 'vue-router' { interface TypesConfig { RouteNamedMap: RouteNamedMap } }source -
BREAKING: IIFE build no longer bundles
@vue/devtools-api— v5 upgraded devtools-api to v8 which has no IIFE build; affects CDN/script-tag setups that relied on the bundled devtools source -
NEW: Query params optional by default (experimental) — v5 file-based routing makes query params optional in typed routes by default source
Also changed: unplugin-vue-router types/utilities moved to vue-router/unplugin (renamed) · route-map.d.ts replaces typed-router.d.ts (renamed) · meta.loaders array on route records for manually connecting data loaders (NEW, experimental) · router.currentRoute is Ref<RouteLocationNormalizedLoaded> — access via .value (v4 BREAKING) · router.onReady() removed — use router.isReady() returning a Promise (v4 BREAKING) · scrollBehavior x/y renamed to left/top (v4 BREAKING)
Best Practices
-
Use
route.metadirectly in guards instead of iteratingto.matched— Vue Router merges all ancestormetafields non-recursively, soto.meta.requiresAuthalready reflects inherited values from parent routes source -
Extend the
RouteMetainterface via module augmentation to type allmetafields — this enforces that every route declares required fields at compile time rather than relying on runtime checks source -
Use
router.beforeResolve(notbeforeEach) for operations that must run after async components are resolved — it fires after all in-component guards and async route components are ready, making it the correct place for camera permission checks or final data validation source -
Use
inject()inside navigation guards (global or per-route) to access Pinia stores and provided values — this is supported since Vue 3.3 and avoids importing stores outside ofsetupcontext source -
Avoid the
nextcallback in guards — return values (false, a route location, or nothing) instead;nextis error-prone because it must be called exactly once per code path and is considered a legacy API source -
await router.push()and check the resolved value to detect navigation failures — the promise resolves to aNavigationFailurewhen blocked, orundefinedon success; useisNavigationFailure(result, NavigationFailureType.aborted)to distinguish the specific failure type source -
Set
props: true(or a function) on route records to decouple components fromuseRoute()— components receiving params as props are reusable and testable without a router instance; use the function form (props: route => ({ query: route.query.q })) to map query params or cast types source -
Watch specific
routeproperties rather than the wholerouteobject —useRoute()returns a reactive object, but watching it entirely triggers on any change (hash, query, params); narrow the watcher to() => route.params.idto avoid unnecessary fetches source -
(experimental) Use
defineBasicLoader/defineColadaLoaderexported from page components for navigation-aware data fetching — loaders exported from lazy-loaded route components are automatically connected to the navigation lifecycle, block the transition until resolved, and exposeisLoading/errorreactively; setlazy: truefor non-critical data that should not block navigation source