Router Plugin and Route Generation

Purpose and Scope

TanStack Router treats the route tree as the application contract: routes are not only matched at runtime, they also describe the typed surface used for navigation, search state, loader data, route context, pending states, and error handling. The build-time plugin and route generation workflow exists to keep that contract synchronized with the files or virtual route definitions a developer edits. The Router API index shows the runtime and authoring functions that consume this contract, including file route creation, lazy route creation, route APIs, link helpers, navigation helpers, and the router factory itself.

Sources: docs/router/api/router.md

For a reader integrating the plugin, the important mental model is that generation happens before ordinary application code relies on the route tree. In file-based routing, route modules define path segments, layouts, loaders, search validation, and components. The generated route map connects those modules to the type system so that links, navigation calls, params hooks, search hooks, and loader-data reads know the same route identifiers. Virtual file routes follow the same goal: they provide a build-time description of routes when a physical file convention is not the best authoring shape, but they still feed the same Router API surface.

Relevant Source Files

  • docs/router/api/router.md — API index for the Router documentation, listing the public functions, components, hooks, and types that route generation ultimately supports.

Core Primitives

The generated route tree becomes useful because it is consumed by a small set of public primitives. The API index lists createFileRoute and createLazyFileRoute for file-oriented route modules, createRoute and createLazyRoute for code-oriented route definitions, createRootRoute and createRootRouteWithContext for the root of the tree, and createRouter for constructing the router instance. It also lists getRouteApi, which is the route-scoped access point for generated types. Together, these names show that generation is not a separate runtime router; it prepares strongly typed inputs for the same Router APIs used throughout an app.

Sources: docs/router/api/router.md

The component and hook lists in the API index explain why generated routes matter beyond initial setup. Link, Navigate, MatchRoute, and Outlet are the component-level consumers of the route tree. Hooks such as useNavigate, useParams, useSearch, useLoaderData, useLoaderDeps, useRouteContext, useMatches, useMatch, useLocation, useRouter, and useRouterState read or act on the current route graph. When the generated tree is current, these APIs can autocomplete paths, narrow params, expose validated search state, and connect loader results to the route that produced them.

Sources: docs/router/api/router.md

System-to-Code Mapping

Build-time concernRuntime/API surfaceWhy it matters
File route modulecreateFileRoute, createLazyFileRouteDeclares a route from a file-based convention while preserving route-specific typing.
Code route modulecreateRoute, createLazyRouteAllows explicit route tree construction without depending on file naming.
Root routecreateRootRoute, createRootRouteWithContextEstablishes the top-level route and shared context contract.
Generated route mapcreateRouter, getRouteApiConnects route definitions to the router instance and route-scoped APIs.
Navigation contractLink, Navigate, useNavigate, LinkOptions, NavigateOptionsEnsures navigation calls target known routes with valid params and search values.
Data and state contractuseLoaderData, useLoaderDeps, useSearch, RouteOptions, RouterStateCarries loader, dependency, search, and state typing through the app.

The mapping is intentionally centered on public names rather than generator internals. A plugin may run inside a supported bundler, watch route files, and emit a generated route tree, but application code should mostly experience the result through Router APIs. That separation is what lets the same conceptual route tree support code-based apps, file-based apps, virtual file route configurations, lazy routes, and route-level code splitting. If a route module changes its path, params, loader result, or search validation, the generated contract is refreshed and the consuming calls reveal mismatches during development.

Sources: docs/router/api/router.md

Execution Flow

A typical plugin-backed workflow starts with authoring route definitions, then letting the build tool run route generation, then importing the generated route tree into the application router setup. The generated file is commonly the bridge between route modules and createRouter. Once the router instance exists, RouterProvider and application components can call the public hooks and render the public components listed in the API index. The key operational rule is to treat generation as part of the development and build loop, not as an optional documentation artifact.

A compact setup usually looks like this: create or update route modules, let the plugin generate the route tree, import that tree, and pass it to the router factory. The generated tree is then the source of truth for typed navigation and route APIs. When using file routes, prefer createFileRoute in route files so the file convention and the route declaration agree. When using lazy boundaries, pair that with lazy route APIs so the generated route map can still represent the split point and the runtime can load the component when needed.

import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
 
export const router = createRouter({
  routeTree,
})

Sources: docs/router/api/router.md

API Components

The API index also shows the adjacent utilities that make generated routes practical in real applications. linkOptions lets teams share strongly typed link configuration instead of rewriting the same destination object in many components. redirect and notFound are route-flow utilities, while isRedirect and isNotFound identify those outcomes. retainSearchParams and stripSearchParams control how search state is preserved or removed across navigation. These utilities are not route generation features by themselves, but they become safer when the generated tree gives every route a known shape.

Sources: docs/router/api/router.md

Types complete the contract by documenting the names a developer will see when configuring or consuming generated routes. RouteOptions, Route, RouteApi, RouteMask, RouteMatch, RouterOptions, RouterState, RouterEvents, LinkOptions, NavigateOptions, ToOptions, ToMaskOptions, ParsedLocation, and history-state types appear in the API index. For plugin users, these types are the reference layer for understanding compile-time errors. If generation reports a route tree correctly but a navigation call fails type checking, the relevant answer is usually in the link, navigation, route, or router option types rather than in the bundler configuration.

Sources: docs/router/api/router.md

Practical Guidance and Next Steps

Use the plugin when the route tree should be derived automatically from route modules or from a virtual route configuration, and use the code-based APIs directly when explicit route construction is clearer. In either mode, keep the generated route map in the same feedback loop as TypeScript, linting, and local development builds. After changing filenames, path params, lazy boundaries, search validation, or loader outputs, confirm that navigation, loader-data reads, and route APIs still type-check. For deeper follow-up, read the file-based routing guide, the file route API reference, and the router API overview before troubleshooting plugin-specific behavior.