JavaScript Development Space

How to Use TanStack Router: A Modern, Type-Safe Router for React

How to Use TanStack Router

TanStack Router: A Modern, Type-Safe Router for React

For React developers, routing is a critical aspect of building applications. While React Router and Next.js Router dominate the ecosystem, a new contender TanStack Router offers a fresh approach. Designed for modern, scalable, and type-safe navigation, it incorporates best practices from solutions like Remix and Next.js.

Key Features of TanStack Router

1. Complete Type-Safety

Built with TypeScript in mind, TanStack Router ensures full type coverage, minimizing runtime errors. IDE support highlights issues like incorrect parameter names or missing query parameters.

2. Built-in Data Loaders and Caching

With API data fetching integrated directly into the router:

  • Supports parallel data loading across routes.
  • Stale-while-revalidate caching out of the box, or integration with TanStack Query.
  • Prefetches data on hover for faster navigation.

3. Advanced Query Parameter Management

TanStack Router offers:

  • JSON serialization for complex objects.
  • Automatic validation of query parameters.
  • Middleware for centralized management of query updates.
  • Declarative and programmatic tools like useSearch and <Link>.

4. SSR Compatibility and Framework Integration

While primarily a client-side router, TanStack Router supports SSR and streaming. Upcoming integrations with frameworks like TanStack Start aim to rival Next.js.

5. Code Splitting and Lazy Loading

  • Critical and non-critical parts of routes can be separated.
  • Supports file-based routing for automatic tree generation.

6. Developer Tools

Includes official devtools to visualize route structures, cache states, and data loaders.

Comparison with Other Solutions

TanStack Router vs. React Router

  • Type Safety: TanStack Router offers full type safety, unlike React Router.
  • Caching: Built-in caching and data loaders outperform React Router’s capabilities.
  • Query Parameters: Comprehensive tools for query management.

TanStack Router vs. Next.js

  • Lightweight: Ideal for client-side routing without the overhead of a full framework.
  • Flexibility: Easier integration into existing SPAs compared to the monolithic Next.js approach.

A detailed comparison can be found here.

Basic Setup

Code-Based Routing

ts
1 import {
2 createRouter,
3 createRootRoute,
4 createRoute,
5 RouterProvider,
6 } from '@tanstack/react-router';
7
8 // Define routes
9 const rootRoute = createRootRoute();
10 const aboutRoute = createRoute({ getParentRoute: () => rootRoute, path: '/about' });
11
12 // Create router instance
13 const router = createRouter({ routeTree: rootRoute.addChildren([aboutRoute]) });
14
15 // Use the router
16 <RouterProvider router={router} />;

File-Based Routing

Structure your routes in a /routes directory, and use a plugin to auto-generate the route tree.

Let's add some routes

ts
1 import { StrictMode } from 'react';
2 import ReactDOM from 'react-dom/client';
3 import {
4 createRouter,
5 createRootRoute,
6 createRoute,
7 RouterProvider,
8 Outlet,
9 Link,
10 } from '@tanstack/react-router';
11
12 import { TanStackRouterDevtools } from '@tanstack/router-devtools';
13
14 // Define the root route with a shared layout
15 const rootRoute = createRootRoute({
16 component: () => (
17 <>
18 <nav>
19 <Link to="/">Home</Link>
20 <Link to="/about">About</Link>
21 </nav>
22 <Outlet />
23 <TanStackRouterDevtools />
24 </>
25 ),
26 });
27
28 // Define child routes
29 const indexRoute = createRoute({
30 getParentRoute: () => rootRoute,
31 path: '/',
32 component: () => <div>Home Page</div>,
33 });
34
35 const aboutRoute = createRoute({
36 getParentRoute: () => rootRoute,
37 path: '/about',
38 component: () => <div>About Us</div>,
39 });
40
41 // Build the route tree
42 const routeTree = rootRoute.addChildren([indexRoute, aboutRoute]);
43
44 // Create the router instance
45 const router = createRouter({ routeTree });
46
47 // Register types for TypeScript compatibility
48 declare module '@tanstack/react-router' {
49 interface Register {
50 router: typeof router;
51 }
52 }
53
54 // Entry point for the application
55 ReactDOM.createRoot(document.getElementById('root')!).render(
56 <StrictMode>
57 <RouterProvider router={router} />
58 </StrictMode>
59 );

This setup creates a simple router with two routes ("/" and "/about"). Each route renders its corresponding component when accessed.

File-Based Routing

For a more magical approach, consider using file-based routing. The folder structure within /src/routes/... defines the hierarchy, and a plugin auto-generates the route tree.

Example structure:

1 src/
2 ┣ routes/
3 ┃ ┣ __root.tsx # Root route
4 ┃ ┣ index.tsx # /
5 ┃ ┗ about.tsx # /about
6 ┣ main.tsx
7 ┗ routeTree.gen.ts (auto-generated)

In __root.tsx, you can define a common layout, headers, footers, Devtools, and other global components.

Fetching Data with Loaders

TanStack Router provides built-in support for loaders, which fetch and cache data before rendering components.

ts
1 // src/routes/posts.tsx
2 import { createFileRoute } from '@tanstack/react-router';
3 import { fetchPosts } from '@/api';
4
5 // Define a route with a loader to fetch posts
6 export const Route = createFileRoute('/posts')({
7 loader: async () => fetchPosts(),
8 component: Posts,
9 });
10
11 function Posts() {
12 // Access loader data
13 const posts = Route.useLoaderData();
14
15 return (
16 <ul>
17 {posts?.map((post) => (
18 <li key={post.id}>{post.title}</li>
19 ))}
20 </ul>
21 );
22 }

With this setup, navigating to /posts triggers data loading and caching before rendering. If revisited during the cache's validity period, no additional fetch requests are needed.

Search Parameter Handling and Validation

Using ?searchQuery=... is an effective way to manage UI state like filters or pagination. With TanStack Router, you can validate query parameters and manipulate them without directly working with URLSearchParams.

Here's an example of a route with validation and a component that updates parameters using useNavigate:

ts
1 // Define a route with search parameter validation
2 const ProductsRoute = createFileRoute('/products')({
3 validateSearch: (search) => ({ ...search, filter: search.filter ?? '' }),
4 component: Products,
5 });
6
7 // Component to read and update query parameters
8 function Products() {
9 const { filter } = ProductsRoute.useSearch();
10 const navigate = useNavigate({ from: ProductsRoute.fullPath });
11
12 function setActiveFilter() {
13 navigate({ search: (old) => ({ ...old, filter: 'active' }) });
14 }
15
16 return (
17 <div>
18 <p>Current Filter: {filter}</p>
19 <button onClick={setActiveFilter}>Active Products</button>
20 </div>
21 );
22 }

With this approach, the filter state is stored in the URL, simplifying sharing, reloading, and collaboration.

Render Optimizations in TanStack Router

TanStack Router incorporates advanced optimization techniques to minimize unnecessary re-renders. Key mechanisms include:

1. Structural Sharing

When search parameters update, TanStack Router preserves references to unchanged parts. For instance, if foo and bar exist in the search parameters and only bar changes, the reference to foo remains the same, reducing re-renders.

2. Fine-Grained Selectors

You can subscribe to specific parts of the state using the select option in hooks. This minimizes re-renders to only when the selected field changes.

ts
1 // Component re-renders only if `foo` changes
2 const foo = Route.useSearch({ select: ({ foo }) => foo });

If bar changes while foo remains unchanged, the component will not re-render.

3. Structural Sharing with Select

When using select, returning a new object each time can cause unnecessary re-renders. Enable structural sharing to let TanStack Router reuse unchanged objects.

Enable globally when creating the router:

ts
1 const router = createRouter({
2 routeTree,
3 defaultStructuralSharing: true,
4 });

Or enable it locally:

ts
1 const result = Route.useSearch({
2 select: (search) => ({
3 foo: search.foo,
4 greeting: `Hello, ${search.foo}`,
5 }),
6 structuralSharing: true,
7 });

Note: Data must be JSON-compatible (e.g., primitives, plain objects, arrays). Non-JSON-compatible data like new Date() will not support structural sharing, and the compiler will warn you.

Devtools

To understand how the router selects routes, loads data, or handles caching and errors, you can use TanStack Router Devtools. These tools display the current route tree, cache state, asynchronous data loads, and errors. Here's an example of how to set them up:

ts
1 import { TanStackRouterDevtools } from '@tanstack/router-devtools';
2
3 function App() {
4 return (
5 <>
6 <RouterProvider router={router} />
7 <TanStackRouterDevtools router={router} />
8 </>
9 );
10 }

The Devtools panel can be toggled open or closed, and its state (open/closed) is stored in localStorage for persistence.

Additional Features

Here’s a summary of advanced capabilities that might be useful for specific scenarios (detailed explanations are available in the official TanStack Router documentation):

1. Virtual File Routes

If regular file-based routing doesn't meet your needs, you can programmatically create route trees. This allows you to combine real files and directories under specific paths.

  • Use cases: Combine virtual and file-based routes or mount standard route folders to custom URLs.

2. Server-Side Rendering (SSR) and Streaming

TanStack Router supports both non-streaming and streaming SSR:

  • Non-streaming SSR: Load data, generate HTML, and hydrate the fully-rendered page on the client.
  • Streaming SSR: Deliver critical content first for faster rendering while loading heavy data in parallel, improving perceived speed.

3. Route Masking

Route masking lets you display one URL to users while routing internally to a different path. Useful for hiding certain details in the URL, such as modal parameters or service-specific queries.

4. Authenticated Routes

Use the beforeLoad function to check user authentication. Redirect unauthorized users to a login page or other content. TanStack Router integrates well with React contexts or state management solutions for handling authentication.

5. Data Mutations

For managing mutations, consider using external tools like TanStack Query or SWR, combined with the router’s cache. After a mutation, call router.invalidate() to refetch updated data seamlessly.

6. Scroll Restoration

TanStack Router simplifies scroll restoration for both entire pages and specific scroll containers. It eliminates the need for custom solutions to manage scroll positions during navigation.

Devtools To understand how the router selects routes, loads data, or handles caching and errors, you can use TanStack Router Devtools. These tools display the current route tree, cache state, asynchronous data loads, and errors. Here's an example of how to set them up:

ts
1 import { TanStackRouterDevtools } from '@tanstack/router-devtools';
2
3 function App() {
4 return (
5 <>
6 <RouterProvider router={router} />
7 <TanStackRouterDevtools router={router} />
8 </>
9 );
10 }

The Devtools panel can be toggled open or closed, and its state (open/closed) is stored in localStorage for persistence.

Additional Features

Here’s a summary of advanced capabilities that might be useful for specific scenarios (detailed explanations are available in the official TanStack Router documentation):

1. Virtual File Routes

If regular file-based routing doesn't meet your needs, you can programmatically create route trees. This allows you to combine real files and directories under specific paths.

  • Use cases: Combine virtual and file-based routes or mount standard route folders to custom URLs.

2. Server-Side Rendering (SSR) and Streaming

TanStack Router supports both non-streaming and streaming SSR:

  • Non-streaming SSR: Load data, generate HTML, and hydrate the fully-rendered page on the client.
  • Streaming SSR: Deliver critical content first for faster rendering while loading heavy data in parallel, improving perceived speed.

3. Route Masking

Route masking lets you display one URL to users while routing internally to a different path. Useful for hiding certain details in the URL, such as modal parameters or service-specific queries.

4. Authenticated Routes

Use the beforeLoad function to check user authentication. Redirect unauthorized users to a login page or other content. TanStack Router integrates well with React contexts or state management solutions for handling authentication.

5. Data Mutations

For managing mutations, consider using external tools like TanStack Query or SWR, combined with the router’s cache. After a mutation, call router.invalidate() to refetch updated data seamlessly.

6. Scroll Restoration

TanStack Router simplifies scroll restoration for both entire pages and specific scroll containers. It eliminates the need for custom solutions to manage scroll positions during navigation.

7. Flexible Error Handling

In addition to classic boundary components (errorComponent, notFoundComponent), you can throw notFound() from loaders or components. TanStack Router will delegate to the nearest “Not Found” handler automatically.

8. External Data Loading

For advanced caching or data fetching, TanStack Router integrates smoothly with TanStack Query, RTK Query, SWR, or Relay. You can pass these clients through the router context and use loaders to prefetch data before rendering.

These features make TanStack Router a versatile and powerful tool for handling even the most complex routing scenarios in modern web applications.

Why Choose TanStack Router?

Ideal for projects emphasizing type safety, optimized data fetching, and query management, TanStack Router complements tools like TanStack Query for a seamless development experience.

By embracing modern practices and offering unmatched flexibility, TanStack Router is a game-changer in React routing.

Conclusion

TanStack Router offers a modern, type-safe approach to building robust routing systems in React applications. With features like data loaders, search parameter validation, SSR support, and built-in optimization mechanisms, it simplifies the development of dynamic, scalable applications. Its seamless integration with tools like React Query, flexible error handling, and scroll restoration ensures a smooth developer experience. Whether you're building simple SPAs or complex enterprise-level applications, TanStack Router provides the tools and flexibility needed to manage routes efficiently. Start exploring its capabilities today to unlock the full potential of your React projects.

JavaScript Development Space

© 2025 JavaScript Development Space - Master JS and NodeJS. All rights reserved.