TanStack/router @tanstack/vue-router
Modern and scalable routing for Vue applications
Version: 1.167.3 (Mar 2026) Deps: @tanstack/vue-store@^0.9.1, @vue/runtime-dom@^3.5.25, isbot@^5.1.22, jsesc@^3.0.2, tiny-invariant@^1.3.3, tiny-warning@^1.0.3, @tanstack/history@1.161.6, @tanstack/router-core@1.167.3 Tags: latest: 1.167.3 (Mar 2026)
References: Docs — API reference, guides
API Changes
This section documents version-specific API changes — prioritize recent major/minor releases.
-
BREAKING:
NotFoundRoute&routerOptions.notFoundRoute— deprecated in v1.x; usenotFoundComponentin route options ordefaultNotFoundComponentincreateRouterinstead source -
DEPRECATED: Router Classes (
Router,Route,RootRoute,FileRoute) — all class-based APIs are deprecated; use factory functionscreateRouter,createRoute,createRootRoute, andcreateFileRouteinstead source -
DEPRECATED:
opts.navigate— thenavigateargument insidebeforeLoadandloaderis deprecated; usethrow redirect({ to: '...' })for navigation-triggered redirects instead source -
DEPRECATED:
parseParams&stringifyParams— top-level route properties deprecated in favor of the nestedparams.parseandparams.stringifyobjects source -
DEPRECATED:
preSearchFilters&postSearchFilters— deprecated in favor ofsearch.middlewaresarray which provides a composable middleware pipeline for transforming search params source -
DEPRECATED:
<ScrollRestoration />component — deprecated; configure scroll restoration viascrollRestoration: trueincreateRouteroptions instead source -
NEW:
protocolAllowlist—createRouteroption acceptingArray<string>of allowed URL protocols (e.g.'https:','mailto:'); absolute URLs with unlisted protocols are blocked to prevent XSS; also exportsDEFAULT_PROTOCOL_ALLOWLISTconstant source -
NEW:
search.middlewares— route option accepting an array of middleware functions({search, next}) => searchfor composable search param transformation when generating links; use withretainSearchParamsandstripSearchParamshelpers source -
NEW:
head,headers,scripts— route option methods for server-side document management;head()injects<meta>,<link>,<style>into<head>;headers()sets HTTP response headers;scripts()injects<script>tags source -
NEW: Validation Adapters —
@tanstack/zod-adapter,@tanstack/valibot-adapter, and@tanstack/arktype-adapterprovide schema-based validation for search params and route params with distinct input/output type inference source -
NEW:
defaultViewTransition—createRouteroption acceptingboolean | ViewTransitionOptionsto enable native View Transitions API (document.startViewTransition()) during navigation; supportstypesarray viaViewTransitionOptionssource -
NEW:
rewrite—createRouteroption accepting{ input?, output? }for bidirectional URL transformation between browser URL and router's internal URL;inputtransforms before matching,outputtransforms before writing to history source -
NEW:
Wrap&InnerWrap—createRouteroptions for injecting global providers;Wrapsurrounds the entire router,InnerWrapwraps inner content and has access to router context and hooks source -
NEW:
codeSplitGroupings— route optionArray<Array<'loader' | 'component' | 'pendingComponent' | 'notFoundComponent' | 'errorComponent'>>for fine-grained control over how lazy-loaded route assets are bundled into chunks source
Also changed: rootRouteWithContext deprecated → use createRootRouteWithContext · useCanGoBack() new experimental hook · defaultRemountDeps new router option · defaultStructuralSharing new router option · search.strict new router option · disableGlobalCatchBoundary new router option · scrollToTopSelectors new router option · composeRewrites new export · ClientOnly / ScriptOnce / HeadContent / Asset new components · SearchSchemaInput tag for optional search params · state.__TSR_key replaces deprecated state.key
Best Practices
-
Use
zodValidator()adapter withfallback()instead of Zod's.catch()for search param validation —.catch()widens types tounknown, losing type inference, whilefallback(z.number(), 1).default(1)retains correct types and makessearchoptional in<Link>props source -
In
loaderDeps, extract only the search params actually used in the loader — returning the entiresearchobject causes the loader to re-run on any search param change, even unrelated ones likeviewModeorsortDirectionsource -
Use
getRouteApi('/your/path')to access route hooks (useLoaderData,useSearch,useParams) in deeply nested components instead of importing theRouteobject — directRouteimports from child components create circular dependencies source -
Enable
defaultStructuralSharing: trueon the router when usingselectin hooks likeuseSearch— without it,selectreturning a new object on every call triggers unnecessary re-renders even when values are unchanged source -
Use
createRootRouteWithContext<YourContextType>()instead ofcreateRootRoutewhen injecting shared dependencies (auth, query client, etc.) — this enforces the context type at router creation time and makescontextavailable with full type inference in all descendantbeforeLoadandloaderfunctions source -
Property order inside
createFileRoute,createRoute, andcreateRootRouteobjects is inference-sensitive:params/validateSearchmust come beforeloaderDeps,beforeLoadbeforeloader, etc. — wrong order causes type errors wherecontextfrombeforeLoadisn't visible inloader. Install@tanstack/eslint-plugin-routerand enable thecreate-route-property-orderrule (it's fixable) source -
Use
retainSearchParams(['key'])andstripSearchParams(defaultValues)assearch.middlewareson a route rather than manually forwarding params in every<Link>— middlewares run automatically on all descendant links and on navigation, keeping the URL clean without repetitive spread patterns source -
When throwing
redirect()insidebeforeLoaderror handlers, always re-throw errors identified byisRedirect()before converting other errors — otherwise intentional redirects are swallowed as route errors source -
Use
linkOptions({ to, search, ... })to define reusable navigation targets instead of plain object literals — bare object literals infertoasstring(matching every route) and defer type errors until the object is spread into<Link>.linkOptionsvalidates the destination at definition time and the same value works in<Link>,navigate(), andredirect()source -
Set
defaultPreload: 'intent'on the router to preload route data and code-split chunks on link hover — preloaded data is cached for 30 seconds (configurable viadefaultPreloadMaxAge) and prevents loader waterfalls on navigation without any per-link configuration source