Start Routing and Entry Points

Purpose and Scope

TanStack Start is the full-stack layer for Router-first applications. In practical terms, that means a Start app still treats the TanStack Router route tree as the application contract: route files define URLs, params, search validation, loaders, components, and navigation behavior, while Start adds server execution around that same contract. The Start documentation describes the added responsibilities as full-document SSR, streaming, server functions, server routes, and deployable runtime output. This page focuses on how to think about routing and entry points when that Router contract is used by a Start application.

The source-backed Router API index is the best anchor for this page because Start routing depends on the same public primitives that Router applications use directly. Route creation functions define the tree, Router creation functions instantiate it, components render matches and navigation, hooks read the active router state, and types describe the public contracts. Start can then run matching, loaders, and rendering on the server before the client resumes the same route tree during hydration and later navigations.

Sources: docs/router/api/router.md

Relevant Source Files

  • docs/router/api/router.md - Lists the public Router API categories used by Start-oriented routing: route creation functions, router creation, rendering components, navigation components, state hooks, and the core option/state/event types.

Core Routing Primitives

A Start route begins with Router primitives, not a separate routing DSL. File-based route modules commonly use createFileRoute, while root files use createRootRoute or createRootRouteWithContext. Code-defined route trees can use createRoute, and route-level lazy loading can use createLazyFileRoute, createLazyRoute, and lazyRouteComponent. These functions are important because they produce the typed route records that Start can match on the server and the client without changing how routes are authored.

The router instance is created through createRouter, and that instance is where options, route tree registration, history integration, and runtime state meet. Start’s client and server entry points should be understood as different runtimes around the same router contract. On the server, the route tree can be matched to an incoming request so loaders, head data, redirects, not-found handling, and streaming can participate in the response. On the client, the same contract powers links, navigation, route state reads, and route data access after hydration.

Rendering and navigation are also Router APIs. The API index lists <Outlet> for nested route composition, <Link> and <Navigate> for declarative navigation, <Await> for async UI, and boundary components such as <CatchBoundary>, <CatchNotFound>, <ErrorComponent>, <NotFoundComponent>, and <DefaultGlobalNotFound>. In a Start app, these remain the component vocabulary for building route UI; Start changes where and when rendering work can happen, but the component tree is still shaped by Router matches and nested outlets.

Sources: docs/router/api/router.md

Entry Point Model

A useful mental model is to split a Start app into three layers. The route modules define the durable application shape. The router entry creates or exports the router instance that knows about that shape. The Start runtime entry points then decide how that router is executed for a given environment: initial document rendering on the server, streaming of HTML and route data, and client hydration followed by normal SPA-style navigation. The same route tree should remain the source of truth across these phases.

For example, a file route can define a URL path, a component, and route behavior with createFileRoute. The Router docs emphasize that the path argument is managed by the bundler plugin or Router CLI in file-based routing, which keeps TypeScript connected to the specific route file. Start builds on that generated or declared route tree. That is why route authors should avoid thinking of “server routes” and “client routes” as separate application maps; Start’s value is that the same map can drive both server rendering and client navigation.

import { createFileRoute } from '@tanstack/react-router'
 
export const Route = createFileRoute('/projects/$id')({
  component: ProjectPage,
  loader: ({ params }) => loadProject(params.id),
})

The client entry point is responsible for mounting or hydrating the application around the router. Once hydrated, user interactions flow through <Link>, <Navigate>, useNavigate, and related navigation APIs. Components read state through hooks such as useLocation, useParams, useSearch, useLoaderData, useRouteContext, useMatches, and useRouterState. The server entry point is responsible for request-time work that can happen before or during the HTML response, including matching routes, running loaders, handling redirects or not-found results, and producing the streamed document.

Sources: docs/router/api/router.md

System-to-Code Mapping

ConcernRouter API surface used by Start appsWhy it matters
Route definitioncreateFileRoute, createRootRoute, createRootRouteWithContext, createRouteDefines the typed route tree that Start treats as the application contract.
Router instancecreateRouter, RouterOptions Type, Router Type, RouterState Type, RouterEvents TypeConnects route definitions to runtime configuration, state, and observation.
Nested rendering<Outlet>, route components, Route Type, RouteMatch TypeLets parent and child routes compose layouts during SSR and client rendering.
Navigation<Link>, <Navigate>, useNavigate, LinkOptions Type, NavigateOptions TypeKeeps client transitions and redirects tied to typed routes.
Data and async UIroute loaders, useLoaderData, useLoaderDeps, <Await>, deferAllows route data to be fetched before render, streamed, cached, or read after navigation.
Errors and control flowredirect, notFound, isRedirect, isNotFound, boundary componentsGives server and client routing a shared language for redirects, missing resources, and failures.

This mapping is intentionally Router-first. Start adds server functions and deployment output, but the routing entry points still depend on the route tree, the router instance, and the public Router APIs for reading and rendering matches. If a Start page needs route params, it should use the same typed params contract as a Router page. If it needs URL state, it should validate and consume search params through the same route/search APIs. If it needs navigation, it should prefer typed links and navigation options rather than constructing URLs by hand.

Sources: docs/router/api/router.md

Execution Flow

During an initial request, the Start server runtime receives a URL and uses the Router route tree to determine the matching branch. Matching gives the runtime access to route params, search state, loader dependencies, route context, and the components or lazy components needed for the response. Loader work can run before render, redirects and not-found results can short-circuit the response, and deferred or streamed data can be represented with Router async primitives such as defer and <Await>. The outcome is an HTML document that reflects the active route branch.

During hydration, the client runtime resumes the already-rendered document with the same router contract. Hooks such as useRouter, useRouterState, useLocation, useMatch, useMatches, useParams, and useSearch provide typed access to the current navigation state. From that point forward, client navigation can preload, fetch, invalidate, and render route data without abandoning the server-rendered foundation. This is the key integration point: the server entry creates the first response, and the client entry continues the application with the same route API vocabulary.

Start server functions are adjacent to this routing flow rather than a replacement for it. The Start product docs describe server functions as explicit, validated server boundaries for database, auth, and environment work. Route loaders can call those server functions or other server-only code when running on the server, while client navigations still interact with the route tree through the Router APIs. Keeping that boundary explicit helps maintain the distinction between local route modules, server-executed work, and the deployable runtime adapter chosen for production.

Compact API Reference

Use this checklist when wiring Start routing and entries around Router primitives. Define the route tree with createFileRoute, createRootRoute, createRootRouteWithContext, or createRoute. Instantiate the router with createRouter. Render nested UI with <Outlet>, use <Link> and <Navigate> for declarative navigation, and use useNavigate for imperative transitions. Read runtime state with useLocation, useParams, useSearch, useLoaderData, useRouteContext, useMatches, useMatch, useRouter, and useRouterState. Model redirects and missing resources with redirect, notFound, isRedirect, and isNotFound.

For Start-specific architecture work, the next step is to connect this Router API surface to the framework package entry files and deployment adapter used by your app. Read the Start overview first if you need the product-level mental model, then move to server functions and rendering/hydration once the route tree and router entry are clear. If a routing issue appears at runtime, debug the generated route tree and the Router state before investigating the server adapter, because Start’s server work is built around the same typed Router contract.

Sources: docs/router/api/router.md