How to Integrate TanStack Router in React
TanStack Router is a modern, type-safe, and performance‑oriented routing solution for React applications. It is built on the same design philosophy as other TanStack libraries: predictable APIs, first‑class TypeScript support, and powerful tooling for data‑driven user interfaces. This article provides a full technical overview of TanStack Router, covering setup, routing models, search‑parameter validation, loaders, SSR, devtools, and advanced features such as structural sharing and route masking.
Why TanStack Router Exists
Traditional routers such as React Router offer flexibility but lack strict type validation and built‑in data mechanisms. Framework routers such as Next.js limit flexibility because routing is tightly coupled to the framework. TanStack Router takes the middle ground: a completely framework‑agnostic, type‑first router for React.
Key goals:
- Provide strong type guarantees at compile time
- Integrate routing with data loading and caching
- Enable declarative search‑parameter management
- Support code splitting, SSR, file‑based routing
- Give developers fine‑grained control without requiring a full framework
Core Features
Type‑Safe Routing
Every route, its path, loader, parameters, and search schema are fully typed. When navigating, incorrect keys, invalid parameters, or missing search fields are caught at compile time.
Built‑In Data Loaders
Routes can define loader() functions that:
- fetch data before rendering
- cache results
- revalidate automatically
- integrate with TanStack Query for complex workflows
Search Parameter Validation
Unlike manually parsing URLSearchParams, TanStack Router allows:
- runtime validation
- default values
- type‑safe updates
- JSON‑compatible search objects
SSR and Streaming
TanStack Router supports:
- non‑streaming SSR: load data → render → hydrate
- streaming SSR: progressively deliver HTML while loaders resolve
Both patterns integrate naturally with existing React SSR methods.
Code Splitting and File‑Based Routing
- routes can be defined in code or generated from files
- lazy imports work seamlessly
- subtree routing supports extremely flexible directory structures
Devtools
A dedicated panel visualizes:
- route tree
- loader states
- cache snapshots
- search parameters
- navigation events
Getting Started
Code‑Based Routing
import {
createRouter,
createRootRoute,
createRoute,
RouterProvider,
} from '@tanstack/react-router';
const rootRoute = createRootRoute();
const aboutRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/about',
});
const router = createRouter({
routeTree: rootRoute.addChildren([aboutRoute]),
});
// Application
<RouterProvider router={router} />;Full Example with Layout, Links, and Devtools
import {
createRouter,
createRootRoute,
createRoute,
RouterProvider,
Outlet,
Link,
} from '@tanstack/react-router';
import { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
import { TanStackRouterDevtools } from '@tanstack/router-devtools';
const rootRoute = createRootRoute({
component: () => (
<>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Outlet />
<TanStackRouterDevtools />
</>
),
});
const indexRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/',
component: () => <div>Home Page</div>,
});
const aboutRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/about',
component: () => <div>About Us</div>,
});
const routeTree = rootRoute.addChildren([indexRoute, aboutRoute]);
const router = createRouter({ routeTree });
declare module '@tanstack/react-router' {
interface Register {
router: typeof router;
}
}
ReactDOM.createRoot(document.getElementById('root')!).render(
<StrictMode>
<RouterProvider router={router} />
</StrictMode>,
);File‑Based Routing
When using file‑based routing, /src/routes becomes the source of truth:
src/
┣ routes/
┃ ┣ __root.tsx
┃ ┣ index.tsx
┃ ┗ about.tsx
┣ main.tsx
┗ routeTree.gen.ts__root.tsx typically contains global layout, headers, and devtools.
Data Loaders
Loaders fetch data before rendering and cache the results.
import { createFileRoute } from '@tanstack/react-router';
import { fetchPosts } from '@/api';
export const Route = createFileRoute('/posts')({
loader: async () => fetchPosts(),
component: Posts,
});
function Posts() {
const posts = Route.useLoaderData();
return (
<ul>
{posts?.map((p) => (
<li key={p.id}>{p.title}</li>
))}
</ul>
);
}Search Parameters and Validation
const ProductsRoute = createFileRoute('/products')({
validateSearch: (search) => ({
...search,
filter: search.filter ?? '',
}),
component: Products,
});
function Products() {
const { filter } = ProductsRoute.useSearch();
const navigate = useNavigate({ from: ProductsRoute.fullPath });
function setActiveFilter() {
navigate({
search: (old) => ({ ...old, filter: 'active' }),
});
}
return (
<div>
<p>Current Filter: {filter}</p>
<button onClick={setActiveFilter}>Active Products</button>
</div>
);
}Render Optimizations
Structural Sharing
If only part of the search object changes, TanStack Router preserves references.
const foo = Route.useSearch({ select: ({ foo }) => foo });Enable globally:
const router = createRouter({
routeTree,
defaultStructuralSharing: true,
});Fine‑Grained Selectors
const result = Route.useSearch({
select: (search) => ({
foo: search.foo,
greeting: `Hi ${search.foo}`,
}),
structuralSharing: true,
});Advanced Features
Virtual File Routes
Programmatically define or merge route directories.
SSR and Streaming
- Non‑streaming renders full HTML before hydration
- Streaming sends HTML chunks progressively
Route Masking
Present one URL while routing internally to a different path.
Auth Routes
Use beforeLoad to guard routes.
Data Mutations
Integrate with TanStack Query, SWR, RTK Query, or Relay. After mutation:
router.invalidate();Scroll Restoration
Automatically preserve scroll position between navigations.
Error Handling
Supports:
-
errorComponent -
notFoundComponent - throwing
notFound()inside loaders
External Data Integrations
Loaders work seamlessly with external clients. Pass them through context for prefetching.
Devtools Integration
import { TanStackRouterDevtools } from '@tanstack/router-devtools';
function App() {
return (
<>
<RouterProvider router={router} />
<TanStackRouterDevtools router={router} />
</>
);
}State persists via localStorage.
Conclusion
TanStack Router delivers a modern, type‑safe routing model that scales with real‑world React applications. Its integration with loaders, fine‑grained state selection, JSON‑safe search parameters, SSR, streaming, and file‑based routing make it one of the most flexible routing tools available. For teams that value type safety, predictable data flows, and compatibility with strong caching tools like TanStack Query, it offers a compelling alternative to traditional routers and framework‑locked solutions.
Explore the official docs to take advantage of its full capabilities.