Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Migrating React Router to Tanstack Router's File-Based Routing

Hello! Let's continue our journey of migrating your SPA to an SSR architecture.

In our last lesson, we conducted a crucial audit of the SPA codebase to identify all dependencies on client-side browser APIs. This gave us a clear "hit list" of code that needs to be refactored or replaced.

With that analysis complete, our next task is to lay down the new foundation of the application: its routing structure. This lesson directly addresses the next learning outcome in our migration module:

Map the route structure of a client-side router (e.g., React Router) to Tanstack Router's file-based conventions.

As an experienced React developer, you're likely very familiar with code-based routing libraries like React Router, where you define your application's paths using JSX components. Tanstack Router takes a different, more structured approach. We will explore this new paradigm and learn how to translate the logic you already know into this powerful file-based system.

1. The Paradigm Shift: From Code to Files

In a typical SPA using React Router, you define your routes declaratively in your code, often in a central location:

// Familiar React Router setup
<Routes>
  <Route path="/" element={<Layout />}>
    <Route index element={<HomePage />} />
    <Route path="about" element={<AboutPage />} />
    <Route path="posts/:postId" element={<PostDetailsPage />} />
    {/* ... more routes */}
  </Route>
</Routes>

Tanstack Router shifts this responsibility from your code to your filesystem. The structure of files and folders within a special src/routes directory dictates your application's URL structure. This might seem unusual at first, but it comes with significant advantages.

TanStack File-Based Routing | TanStack Router React Docs

To understand the philosophy behind this approach, let's start with the official documentation on File-Based Routing. It explains the core benefits of this paradigm.

Read the routing overview in the introduction and the section 'What is File-Based Routing?'. Pay attention to the listed benefits, particularly code-splitting and type-safety, as they are major motivators for this design.

The key takeaway is that by enforcing a structure, Tanstack Router can automate code-splitting and generate type definitions for all your routes, which is a massive boost for maintainability and developer experience in large applications.

2. The Core Building Blocks

Before we start mapping, let's understand the three fundamental pieces of Tanstack Router's structure:

  1. The src/routes Directory: This is the designated folder where all your route definitions will live. Tanstack Router's build plugin exclusively watches this directory.
  2. The __root.tsx File: This is a special file that must exist at the top level of the src/routes directory. It defines the root layout of your entire application—the equivalent of a top-level layout component in React Router that might render a navbar, a footer, and an <Outlet /> for child routes to be rendered into.
  3. The routeTree.gen.ts File: This file is auto-generated by Tanstack Router. You should never edit it. It contains all the type information for your routes, derived from the files you create in the src/routes directory. This is what enables the powerful type-safe navigation we'll see later.

This video provides a clear walkthrough of how these fundamental pieces fit together.

Tanstack Router in React (Complete Tutorial)

This video from Cosden Solutions demonstrates the initial setup and the roles of the fundamental files that form the basis of file-based routing.

First, watch the initial setup to understand the roles of the src/routes folder and the __root.tsx file. Then, skip ahead and watch the RouterProvider integration to see how these pieces are connected in the main application entry point (main.tsx) via the RouterProvider.

3. Mapping Common Route Patterns

Now, let's get practical. We'll take a hypothetical but realistic React Router v6 configuration and translate it, piece by piece, into Tanstack Router's file conventions.

Our SPA's React Router configuration:

<Routes>
  {/* Main application layout */}
  <Route path="/" element={<AppLayout />}>
    {/* 1. Index Route */}
    <Route index element={<HomePage />} />
    {/* 2. Static Route */}
    <Route path="about" element={<AboutPage />} />
    
    {/* 3. Nested Routes with a Layout */}
    <Route path="posts" element={<PostsLayout />}>
      <Route index element={<PostListPage />} />
      {/* 4. Dynamic Route */}
      <Route path=":postId" element={<PostDetailsPage />} />
    </Route>

    {/* 5. Pathless Layout for Auth */}
    <Route element={<AuthGuard />}>
        <Route path="dashboard" element={<DashboardPage />} />
        <Route path="profile" element={<ProfilePage />} />
    </Route>

    {/* 6. Catch-all Route */}
    <Route path="*" element={<NotFoundPage />} />
  </Route>
</Routes>

Here is how we map each part to the src/routes directory structure:

Mapping Static and Index Routes

  • path="/" (Index): Becomes src/routes/index.tsx. The index filename is a special token that matches the parent directory's path exactly.
  • path="about" (Static): Becomes src/routes/about.tsx. The filename directly corresponds to the URL path segment.

This is the most straightforward mapping.

Mapping Nested Routes: Directory vs. Flat

For the /posts section, we have a nested structure. Tanstack Router provides two ways to achieve this:

  1. Directory-based (Recommended for organization): You create a folder for the parent route.
    • /posts layout: src/routes/posts/route.tsx
    • /posts index page: src/routes/posts/index.tsx
  2. Flat-file (Good for reducing folder depth): You use dots (.) in the filename to denote nesting.
    • /posts layout: src/routes/posts.tsx
    • /posts index page: src/routes/posts.index.tsx

Both approaches are valid, and you can even mix them.

TanStack File-Based Routing | TanStack Router React Docs

The choice between directory-based and flat-file routing is a key structural decision. The official documentation provides clear examples of both styles.

Read the sections '/s or .s?' covering dot notation, 'Directory Routes' covering directory hierarchy, 'Flat Routes' covering flat hierarchy, and 'Mixed Flat and Directory Routes' covering mixed approaches. Compare the file structures in the tables to understand the trade-offs.

Mapping Dynamic Routes (Path Parameters)

  • path=":postId": Becomes src/routes/posts/$postId.tsx. The dollar sign ($) prefix indicates that this part of the URL is a dynamic parameter. The name following the $ becomes the parameter name (e.g., postId).

This video clearly demonstrates the creation of nested folders and dynamic route files.

Tanstack Router in React (Complete Tutorial)

Let's see how to handle dynamic segments in the URL, like a post ID. This video shows how to create a posts folder for grouping and then use the special $ notation for the dynamic file.

Watch nested dynamic routes. Focus on how a posts folder is created and how posts/$postId.tsx is used to represent a dynamic route.

Mapping Advanced Patterns: Pathless Layouts

In our example, the <AuthGuard /> route provides a layout/logic wrapper for /dashboard and /profile without adding a segment to the URL. This is a very common pattern for authentication.

  • Pathless Layout: Tanstack Router handles this with an underscore (_) prefix on a folder name. We would create a folder src/routes/_auth, and inside it, a route.tsx file to contain the auth logic. The routes for dashboard and profile would then be placed inside this _auth folder.
    • src/routes/_auth/route.tsx (contains the auth check logic and an <Outlet />)
    • src/routes/_auth/dashboard.tsx (maps to /dashboard)
    • src/routes/_auth/profile.tsx (maps to /profile)

The underscore tells the router to use the layout but to not include _auth in the final URL path.

Complete TanStack Router Tutorial - Build Type-Safe React Apps with File-Based Routing

This concept of 'pathless layouts' is extremely powerful for migrations. This video demonstrates exactly how to implement a shared authentication check without affecting the URL structure.

Watch the explanation of pathless layouts. Pay close attention to the use of the _o folder. The underscore prefix is the key convention that makes this a pathless layout.

4. Translation Summary

To consolidate these concepts, here is a quick-reference table mapping React Router v6 patterns to Tanstack Router file conventions.

React Router v6 (<Route>) Tanstack Router File Convention Example (src/routes/...)
path="/" (index route) index.tsx index.tsx
path="about" about.tsx about.tsx
path="posts" (with <Outlet />) posts/route.tsx or posts.tsx posts/route.tsx
path=":postId" $postId.tsx posts/$postId.tsx
path="*" (splat/catch-all) $.tsx $.tsx
Layout Route (no path) _folderName/route.tsx _auth/route.tsx
Organizational Folder (folderName)/... (marketing)/about.tsx

The last item, Organizational Folder, uses parentheses to group files in your project structure without affecting the URL, which is useful for keeping related but publicly separate routes together (e.g., (marketing) vs. (app)).

For a complete list of all file naming rules, the official documentation is the ultimate source of truth.

File Naming Conventions | TanStack Router React Docs

For a comprehensive reference of all possible file naming conventions, the official documentation provides a detailed table. It's a great resource to bookmark for future use.

Review the table in this document. It covers everything we've discussed (__root, $, _, ()) and more. You don't need to memorize it all now, but be aware of what's possible.

Conclusion

You now have a mental model and a practical guide for translating a client-side route configuration into Tanstack Router's file-based system. This is a foundational step that brings much-needed structure and type-safety to your application before we begin migrating more complex logic.

Key Takeaways:

  • Tanstack Router uses the file and folder structure within src/routes to define the application's routes.
  • Simple routes map directly (/about -> about.tsx).
  • Dynamic parameters are denoted with a $ prefix (:id -> $id.tsx).
  • Nested routes can be created with folders (e.g., posts/index.tsx) or dot notation (e.g., posts.index.tsx).
  • Pathless layouts, crucial for auth, are created with an _ prefix on a folder (e.g., _auth/dashboard.tsx maps to /dashboard).

Next Up:

With our new route structure mapped out, the next logical step is to move our data-fetching logic out of the components and into the routes themselves. In the next lesson, we will learn how to convert client-side data fetching patterns (e.g., useQuery in components) to server-side fetching in route loaders. This is where we'll start to see the major performance benefits of SSR.

Can't find a good explanation? Sign up and we'll make it for you

Sign up