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

File-Based Routing with Tanstack Router

Hello! Welcome back.

In our previous lessons, we established the architectural differences between CSR and SSR and demystified the React hydration process. You now have the conceptual foundation for why server-rendered applications are built the way they are.

Today, we'll move from theory to practice by setting up the navigational backbone of our application. The learning outcome for this lesson is to integrate Tanstack Router into a React application and define routes using its file-based conventions.

This is a crucial step. A robust, SSR-friendly router is the first major component we need. You'll learn how Tanstack Router uses a modern, file-system-based approach—similar to frameworks like Next.js—to create a highly organized, scalable, and type-safe routing system.

1. The Philosophy of File-Based Routing

Before we write any code, let's understand the core concept. If you've used react-router-dom, you're likely accustomed to defining your route hierarchy in a central JavaScript or TypeScript file. File-based routing takes a different approach.

TanStack File-Based Routing | TanStack Router React Docs

The official TanStack Router documentation provides the best overview of what file-based routing is and why it's the recommended approach. This will give you a clear understanding of its benefits.

Please read the section titled 'What is File-Based Routing?' to explore the configuration benefits. Focus on the list of benefits, especially Organization, Code-Splitting, and Type-Safety.

As you read, the key takeaway is that the structure of your files and folders in a specific directory (src/routes) directly maps to the URL structure of your application. This convention-over-configuration approach simplifies route management and enables the router to automatically generate type definitions, which we'll see in action shortly.

2. Project Setup and Configuration

Let's integrate Tanstack Router into a fresh React project. We'll use Vite for our bundler, as it's fast and well-supported by the Tanstack ecosystem.

The following video provides a complete walkthrough of the manual setup process. Since you have extensive experience, we'll treat this as a guided exercise. I'll outline the key steps, and you can use the video to see them in action.

Tanstack Router in React (Complete Tutorial)

This tutorial from Cosden Solutions is a clear, step-by-step guide to adding Tanstack Router to a standard React + Vite project. It covers the essential configuration that enables file-based routing.

Watch the basic setup from the beginning, and then skip ahead to the entry point. These segments cover the four critical setup steps: Installation of dependencies. Vite Plugin Configuration in vite.config.ts. Creating the Root Layout (__root.tsx). Updating the App Entry Point (main.tsx) to use the RouterProvider. Feel free to code along with the video.

Let's summarize the critical steps from the video.

Step 1: Installation

First, create a new React + TypeScript project with Vite and install the necessary packages.

# 1. Create a new Vite project
npm create vite@latest my-tanstack-app -- --template react-ts
cd my-tanstack-app

# 2. Install Tanstack Router and its devtools
npm install @tanstack/react-router @tanstack/react-router-devtools

# 3. Install the Vite plugin as a dev dependency
npm install -D @tanstack/router-plugin

Step 2: Vite Plugin Configuration

The @tanstack/router-plugin is the engine that scans your files and generates the route tree. It must be added to your vite.config.ts. Crucially, it must come before the React plugin.

// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { TanStackRouterVite } from '@tanstack/router-plugin/vite'

export default defineConfig({
  plugins: [
    // The TanStack Router plugin must be first
    TanStackRouterVite(),
    react(),
  ],
})

Step 3: Create the Root Layout

All routes will be placed in the src/routes directory. The root layout is a special file that acts as the shell for your entire application. It's where you'd put shared UI like headers, footers, and navigation bars.

Create the file src/routes/__root.tsx:

// src/routes/__root.tsx
import { createRootRoute, Link, Outlet } from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'

export const Route = createRootRoute({
  component: () => (
    <>
      <div className="p-2 flex gap-2">
        <Link to="/" className="[&.active]:font-bold">
          Home
        </Link>{' '}
        <Link to="/about" className="[&.active]:font-bold">
          About
        </Link>
      </div>
      <hr />
      <Outlet />
      <TanStackRouterDevtools />
    </>
  ),
})

The Outlet component, likely familiar from react-router-dom, is the placeholder where the content of child routes will be rendered.

Step 4: Configure the App Entry Point

Finally, we need to tell our React application to use the router. Modify src/main.tsx to create a router instance and provide it to the application.

// src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { RouterProvider, createRouter } from '@tanstack/react-router'

// Import the generated route tree
import { routeTree } from './routeTree.gen'

// Create a new router instance
const router = createRouter({ routeTree })

// Register the router instance for type safety
declare module '@tanstack/react-router' {
  interface Register {
    router: typeof router
  }
}

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>,
)

You will see an error on import { routeTree } from './routeTree.gen'. This is expected! The routeTree.gen.ts file doesn't exist yet. It will be generated automatically when we start the development server.

3. Defining Routes by Convention

With the setup complete, we can now define our application's routes simply by creating files.

The Magic of routeTree.gen.ts

Start the development server:
npm run dev

When you run this command, the Vite plugin will scan your src/routes directory and generate the src/routeTree.gen.ts file. This file contains a typed representation of your entire route structure. You should never edit this file manually.

Creating Basic and Dynamic Routes

Let's create a few routes to see this in action. The process is demonstrated in both of the following videos, giving you two perspectives on the same conventions.

TanStack Start Is Amazing For Full-Stack Apps

This video from ByteGrad, though focused on TanStack Start, does an excellent job of demonstrating the core file-based routing conventions for index, basic, and dynamic routes.

Watch the segments on the home route and post routing. These segments cover: The index.tsx file for the home page. Creating a simple /posts route. Creating a dynamic /posts/$id route. The important distinction of using posts.index.tsx for exact path matching.

Here's a summary of the file conventions:

  1. Index Route (/): Create src/routes/index.tsx.

    // src/routes/index.tsx
    import { createFileRoute } from '@tanstack/react-router'
    
    export const Route = createFileRoute('/')({
      component: () => <div>Hello from the Home Page!</div>,
    })
    
  2. Simple Route (/about): Create src/routes/about.tsx.

    // src/routes/about.tsx
    import { createFileRoute } from '@tanstack/react-router'
    
    export const Route = createFileRoute('/about')({
      component: () => <div>Hello from the About Page!</div>,
    })
    
  3. Dynamic Route (/posts/$postId): Dynamic segments are prefixed with a $.

    • Create a folder src/routes/posts.
    • Inside it, create a file src/routes/posts/$postId.tsx.
    // src/routes/posts/$postId.tsx
    import { createFileRoute } from '@tanstack/react-router'
    
    export const Route = createFileRoute('/posts/$postId')({
      component: PostComponent,
    })
    
    function PostComponent() {
      const { postId } = Route.useParams()
      return <div>Post ID: {postId}</div>
    }
    
  4. Index Route for a Folder (/posts): To create a page for the /posts path itself, you create an index.tsx file inside the posts folder.

    // src/routes/posts/index.tsx
    import { createFileRoute, Link } from '@tanstack/react-router'
    
    export const Route = createFileRoute('/posts/')({
      component: PostsIndex,
    })
    
    function PostsIndex() {
      return (
        <div>
          <h3>Posts</h3>
          <ul>
            <li><Link to="/posts/$postId" params={{ postId: '1' }}>Post 1</Link></li>
            <li><Link to="/posts/$postId" params={{ postId: '2' }}>Post 2</Link></li>
          </ul>
        </div>
      )
    }
    

Directory vs. Flat Routes

Tanstack Router offers flexibility. You can create nested routes using folders or by using . in the filename.

  • Directory Style: src/routes/posts/$postId.tsx
  • Flat Style: src/routes/posts.$postId.tsx

Both achieve the same result. The flat style can be convenient for preventing deeply nested folder structures. You can mix and match these styles as you see fit.

The official documentation provides excellent comparison tables for these conventions.

TanStack File-Based Routing | TanStack Router React Docs

This documentation page provides clear tables that contrast the directory, flat, and mixed routing styles. It's a great reference to have handy.

Quickly review the tables under the 'Directory Routes', 'Flat Routes', and 'Mixed Flat and Directory Routes' sections. You don't need to memorize them, just be aware of the different conventions.

At this point, your project should have a working router with several pages you can navigate between using the links in the root layout.

Conclusion

In this lesson, we successfully integrated Tanstack Router and established a routing structure using its powerful file-based conventions. This approach provides excellent organization and type-safety out of the box, setting a solid foundation for our SSR application.

Key Takeaways:

  • File-Based Routing: The file and folder structure inside src/routes directly defines the application's URL paths.
  • Essential Setup: Configuration involves installing the router, adding the Vite plugin, creating a __root.tsx layout, and updating main.tsx with the RouterProvider.
  • routeTree.gen.ts: This auto-generated file is the source of truth for your route structure and provides full type-safety. It is managed by the router plugin and should not be edited.
  • Route Conventions:
    • index.tsx creates a route for the directory it's in.
    • $param.tsx creates a dynamic route segment.
    • Folders and . notation can both be used for nesting.

In our next lesson, we will dive deeper into implementing type-safe navigation and parameter handling using Tanstack Router's APIs. We'll explore the <Link> component's advanced features and see how the type-safety from our file-based routes makes navigation robust and error-free.

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

Sign up