# Building the Frontend of CodeLens AI with TanStack Start

Before diving into the implementation of the CodeLens AI frontend, let's first look at how the frontend project is organized.

The frontend is built inside a **pnpm monorepo**, which allows the project to keep the web application, backend server, and WebSocket service in separate packages while managing them from a single repository.

For the frontend, we're using **TanStack Start**, **TanStack Router**, **TanStack Query**, **Shadcn** and **Tailwind CSS**.

The goal of this setup is to keep the frontend modular, type-safe, and easy to maintain as the application grows.

* * *

### Project Architecture

The project follows a monorepo structure:

```plaintext
CodeLens-AI/
├── packages/
│   ├── web/
│   ├── server/
│   
├── package.json
├── pnpm-workspace.yaml
└── pnpm-lock.yaml
```

Each package has a specific responsibility:

*   `web` → Frontend application
    
*   `server` → Backend/API server
    

This allows us to develop and manage different parts of the system independently while keeping everything inside one repository.

* * *

### Why a Monorepo?

Instead of creating separate repositories for the frontend, backend service, we keep them together in a single repository.

This gives us:

*   Shared configuration
    
*   Easier dependency management
    
*   Consistent tooling
    
*   Easier local development
    
*   A single Git history
    
*   Ability to share code between packages later
    

For example, if the frontend and backend eventually need shared TypeScript types, we can introduce another package:

```plaintext
packages/
├── web/
├── server/
└── shared/
```

The `shared` package could contain things like API types, schemas, or common utilities.

* * *

### Step1: Setting Up pnpm

The first step was installing the project dependencies:

```plaintext
pnpm install
```

Then I initialized the root package:

```plaintext
pnpm init
```

This created the root `package.json`.

The root `package.json` contains the configuration that applies to the entire repository.

For example:

```plaintext
{
  "name": "CodeLens-AI",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev:web": "pnpm --filter web dev",
    "lint": "pnpm --filter web lint",
    "check": "oxfmt --check",
    "format": "oxfmt",
    "lint:fix": "pnpm --filter web \"lint:fix\"",
    "prepare": "lefthook install"
  }
}
```

* * *

**What is** `pnpm --filter web`**?**

One of the useful features of pnpm workspaces is the `--filter` option.

For example:

```plaintext
pnpm --filter web dev
```

means:

> Run the `dev` script from the package named `web`.

So instead of navigating into:

```plaintext
cd packages/web
pnpm dev
```

we can run it directly from the repository root:

```plaintext
pnpm --filter web dev
```

This becomes particularly useful as the monorepo grows.

For example:

```plaintext
pnpm --filter web dev
pnpm --filter web lint
```

The first command starts the frontend, while the second runs the frontend's linting process.

* * *

**pnpm Workspace Configuration**

To tell pnpm which directories belong to the monorepo, we create:

```plaintext
pnpm-workspace.yaml
```

The configuration is:

```plaintext
packages:
  - "packages/*"

allowBuilds:
  lefthook: true
```

The first part:

```plaintext
packages:
  - "packages/*"
```

basically tells pnpm:

> Treat the packages inside `packages/` as workspace packages.

So these become workspace packages:

```plaintext
packages/
├── web/
├── server/
```

* * *

**Why** `pnpm-lock.yaml`**?**

pnpm also generates:

```plaintext
pnpm-lock.yaml
```

The lockfile records the exact dependency versions used by the project.

This helps ensure that different developers and CI environments install consistent dependency versions.

Instead of one developer getting one version and another developer getting a slightly different version, the lockfile keeps the dependency tree reproducible.

* * *

**Code Quality and Git Hooks**

Once the basic monorepo structure was ready, the next step was setting up development tooling.

CodeLens AI uses:

*   **Oxlint** → linting
    
*   **Oxfmt** → formatting
    
*   **Lefthook** → Git hooks
    

The goal is to catch problems automatically before code reaches the repository.

* * *

**Why Lefthook?**

In a team project, we don't want developers to manually remember:

```plaintext
pnpm lint
pnpm format
```

before every commit.

Instead, Git hooks can automatically run checks.

```plaintext
Developer
    |
    | git commit
    v
Lefthook
    |
    v
Run configured checks
    |
    ├── Pass → Commit
    |
    └── Fail → Stop commit
```

For example, if linting finds an error, the commit can be blocked until the developer fixes the problem.

* * *

**Why Lefthook Instead of Husky?**

**Husky** is a popular Git hook manager, but Lefthook is another alternative.

A Git hook manager allows us to configure commands that automatically execute during Git events such as:

```plaintext
git commit
git push
```

For this project, I chose **Lefthook** to manage these Git hooks.

The important idea isn't the specific tool. The important idea is:

> Automate development checks instead of relying on developers to remember them manually.

* * *

**Why Is Lefthook Installed at the Root?**

Because this is a monorepo, Git belongs to the entire repository rather than an individual package.

Therefore, Git hooks are generally configured at the repository root.

```plaintext
CodeLens-AI/
│
├── packages/
│   ├── web/
│   ├── server/
│   └── websocket/
│
├── lefthook.yml
└── package.json
```

This allows one Git hook configuration to control checks across the entire monorepo.

* * *

**The** `prepare` **Script**

The root `package.json` contains:

```plaintext
{
  "scripts": {
    "prepare": "lefthook install"
  }
}
```

`prepare` is a package-manager lifecycle script.

When another developer clones the repository and runs:

```plaintext
pnpm install
```

the lifecycle becomes:

```plaintext
pnpm install
      |
      v
Dependencies installed
      |
      v
prepare script
      |
      v
lefthook install
      |
      v
Git hooks configured
```

This means developers don't need to manually remember to run:

```plaintext
lefthook install
```

after installing the project.

* * *

**pnpm 11 and** `allowBuilds`

While setting up Lefthook, I encountered an issue with pnpm 11:

```plaintext
ERR_PNPM_IGNORED_BUILDS
Ignored build scripts: lefthook
```

This happens because some dependencies need to execute installation/build scripts.

For security reasons, pnpm can block these scripts unless they are explicitly allowed.

The workspace configuration therefore contains:

```plaintext
allowBuilds:
  lefthook: true
```

This tells pnpm:

> Lefthook is trusted to execute its required build/install script.

Another way to manage these approvals is:

```plaintext
pnpm approve-builds
```

pnpm then shows dependencies requesting permission to execute scripts.

* * *

**Why Does pnpm Restrict Build Scripts?**

Consider a dependency containing:

```plaintext
{
  "scripts": {
    "postinstall": "some-command"
  }
}
```

If package installation scripts were automatically trusted, a malicious package could potentially execute unwanted commands on a developer's machine.

The security model is roughly:

```plaintext
Dependency installed
        |
        v
Wants to execute script
        |
        v
   pnpm checks
        |
     Approved?
      /    \
    YES     NO
     |       |
   Run     Block
```

This is particularly important in large projects where the dependency tree can contain hundreds or thousands of packages.

* * *

**Why Oxfmt at the Root?**

Formatting is slightly different from application-specific linting.

Oxfmt is used as a repository-level formatting tool:

```plaintext
{
  "scripts": {
    "check": "oxfmt --check",
    "format": "oxfmt"
  }
}
```

So we can format the repository from the root:

```plaintext
pnpm format
```

and check formatting with:

```plaintext
pnpm check
```

The distinction is:

```plaintext
Oxlint
   ↓
Checks application/source code
   ↓
packages/web

Oxfmt
   ↓
Formats repository code
   ↓
Root
```

This separation becomes more useful as more packages are added to the monorepo.

* * *

### **Step2: Setting Up the Web Package**

After setting up the monorepo, I created the frontend package:

```plaintext
packages/web/
```

This package contains the CodeLens AI frontend.

The frontend is built using:

```plaintext
TanStack Start
       |
       ├── TanStack Router
       ├── TanStack Query
       └── React
```

This gives us routing, server/client rendering capabilities, and server-state management while keeping the frontend strongly typed.

* * *

**Understanding the Web Package Structure**

After setting up the monorepo, I created the `web` package for the CodeLens AI frontend.

The frontend uses **React with TanStack Start**, with TanStack Router handling the application's routing.

The structure currently looks like this:

```plaintext
CodeLens-AI/
├── packages/
│   ├── server/              ← Backend/server package
│   │
│   └── web/                 ← Frontend + TanStack Start
│       │
│       ├── src/
│       │   ├── routes/
│       │   │   ├── root.tsx
│       │   │   └── index.tsx
│       │   │
│       │   ├── router.tsx
│       │   ├── routeTree.gen.ts
│       │   └── styles.css
│       │
│       ├── package.json
│       ├── vite.config.ts
│       ├── tsconfig.json
│       └── ...
│
├── package.json
├── pnpm-workspace.yaml
└── pnpm-lock.yaml
```

### `web`

The `web` package contains the React/TanStack Start application.

All frontend-specific code lives inside this package, keeping it separate from the backend and other services.

* * *

**File-Based Routing with TanStack Router**

TanStack Router uses **file-based routing**, which means the files inside the `routes` directory represent routes in the application.

For example:

```plaintext
routes/
├── index.tsx       → /
├── about.tsx       → /about
└── dashboard.tsx   → /dashboard
```

So instead of manually defining every route in one large routing configuration, the application's file structure itself represents the routing structure.

This becomes especially useful as the application grows because routes can be organized naturally using folders and files.

* * *

`root.tsx`

`root.tsx` is the **root route** of the application.

It acts as the top-level layout for the routes and is a place for functionality that should be common across the application.

For example, it can contain:

*   Global layouts
    
*   Navigation
    
*   Common providers
    
*   Application-wide UI
    
*   Error and loading boundaries
    
*   Document-level configuration
    

In CodeLens AI, the root route provides the foundation around which the rest of the application's routes are rendered.

* * *

`index.tsx`

The `index.tsx` file represents the root `/` route.

```plaintext
routes/
└── index.tsx → /
```

This is typically the page users see when they visit the application's base URL.

* * *

`router.tsx`

The `router.tsx` file is responsible for creating and configuring the TanStack Router instance.

Conceptually, its job is:

```plaintext
URL
 ↓
TanStack Router
 ↓
Find matching route
 ↓
Render corresponding component
```

For example:

```plaintext
/user/profile
      ↓
TanStack Router
      ↓
routes/user/profile.tsx
      ↓
Profile Page
```

This file is also where router-level configuration such as preloading and scroll restoration can be defined.

* * *

`routeTree.gen.ts`

`routeTree.gen.ts` is a **generated file** created by TanStack Router's tooling.

It represents the application's route tree based on the files inside the `routes` directory.

Conceptually:

```plaintext
routes/
├── index.tsx
├── about.tsx
└── dashboard.tsx
        ↓
TanStack Router tooling
        ↓
routeTree.gen.ts
```

The generated route tree allows TanStack Router to understand the application's routes and provide type-safe routing.

Because this file is generated automatically, we generally **don't edit it manually**. Instead, we modify the route files and let TanStack Router regenerate the route tree.

* * *

**Putting It Together**

The relationship between these files can be summarized as:

```plaintext
TanStack Start
      |
      v
TanStack Router
      |
      v
routes/
      |
      ├── root.tsx
      ├── index.tsx
      └── other routes
      |
      v
Generated Route Tree
      |
      v
Application UI
```

This gives the frontend a clear separation between the application's route structure, router configuration, and individual pages.

* * *

### Step3: How Does the Application Flow Work?

Now that we understand the purpose of each file, let's see what happens when a user actually opens the application.

Suppose a user visits:

```plaintext
/
```

The high-level flow looks like this:

```plaintext
User opens /
      ↓
Application starts
      ↓
router.tsx
      ↓
routeTree.gen.ts
      ↓
__root.tsx
      ↓
index.tsx
      ↓
Home Page
```

Let's understand each step.

**1\. User Opens** `/`

The user opens the CodeLens AI application in their browser:

```plaintext
https://codelens-ai.com/
```

The browser requests the `/` route from the application.

* * *

**2\. Application Starts**

TanStack Start initializes the application.

The router configuration is created in:

```plaintext
src/router.tsx
```

This is where we create the TanStack Router instance and provide the application's route tree.

* * *

**3\.** `router.tsx`

The router is responsible for understanding the application's routes.

Conceptually:

```plaintext
URL: /
   ↓
TanStack Router
   ↓
Which route matches "/"?
```

The router uses the generated route tree to find the matching route.

* * *

**4\.** `routeTree.gen.ts`

TanStack Router generates the route tree from the files inside the `routes` directory.

For example:

```plaintext
routes/
├── __root.tsx
├── index.tsx
└── dashboard.tsx
```

The generated route tree understands that:

```plaintext
/            → index.tsx
/dashboard   → dashboard.tsx
```

So when the user requests `/`, TanStack Router knows that `index.tsx` is the route that should render.

* * *

**5\.** `__root.tsx`

Before rendering the individual page, the root route is involved.

`__root.tsx` acts as the application's top-level route/layout.

This is where we can define things that should be available across multiple routes, such as:

*   Global providers
    
*   Navigation
    
*   Theme provider
    
*   Common layouts
    
*   Global UI
    
*   Document configuration
    

Conceptually:

```plaintext
__root.tsx
     |
     └── Child Route
           |
           └── index.tsx
```

* * *

**6\.** `index.tsx`

Because the user requested `/`, TanStack Router matches the index route:

```plaintext
routes/index.tsx
       ↓
      /
```

The component inside `index.tsx` is rendered as the page content.

* * *

**7\. Home Page**

Finally, the user sees the Home Page in the browser.

So the complete flow is:

```plaintext
User
  |
  | opens /
  ↓
TanStack Start
  |
  ↓
router.tsx
  |
  ↓
routeTree.gen.ts
  |
  ↓
__root.tsx
  |
  ↓
index.tsx
  |
  ↓
Home Page
```

This is the basic flow of how a URL gets translated into a rendered page in the CodeLens AI frontend.

As more routes are added, the same routing mechanism handles them:

```plaintext
/                → index.tsx
/dashboard       → dashboard.tsx
/settings        → settings.tsx
/reviews         → reviews.tsx
```

This file-based routing approach keeps the application's URL structure closely aligned with its code structure.

* * *

### Step4. Shadcn Setup

After setting up the `web` package with **TanStack Start**, the project already had Tailwind CSS configured as part of the frontend template.

I then initialized **shadcn/ui** using:

```plaintext
pnpm dlx shadcn@latest init --preset b0 --template start
```

I wanted to understand what this command actually does, especially how shadcn works with a **Tailwind CSS v4** project.

* * *

**What happens when you run this command?**

Roughly, the shadcn initialization does the following:

```plaintext
shadcn init
    │
    ├── creates components.json
    │
    ├── creates src/lib/utils.ts
    │
    ├── configures shadcn components
    │
    ├── modifies global CSS
    │
    └── configures the shadcn theme for Tailwind v4
```

An important point is that **Tailwind CSS was already present in the project** through the TanStack Start template.

So shadcn is not installing Tailwind from scratch. Instead, it configures shadcn/ui to work with the existing Tailwind CSS setup.

* * *

**Where is** `tailwind.config.js`**?**

This is where Tailwind CSS v4 is different from Tailwind CSS v3.

**Tailwind CSS v3**

In Tailwind v3, you would normally have a:

```plaintext
tailwind.config.js
```

For example:

```js
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};
```

And the global CSS typically contained:

```plaintext
@tailwind base;
@tailwind components;
@tailwind utilities;
```

The JavaScript configuration file was the main place for configuring Tailwind.

* * *

**Tailwind CSS v4 Changed This**

This project uses:

```plaintext
"tailwindcss": "^4.1.18"
```

Therefore, it is using **Tailwind CSS v4**.

Tailwind v4 introduced a **CSS-first configuration approach**.

Instead of relying primarily on:

```plaintext
tailwind.config.js
```

the configuration can be defined directly in CSS.

In this project, the important file is:

```plaintext
src/
└── styles.css
```

It contains:

```plaintext
@import "tailwindcss";
```

This imports Tailwind CSS into the application.

* * *

**How Does Tailwind Get Connected to Vite?**

Tailwind v4 provides a dedicated Vite integration:

```plaintext
"@tailwindcss/vite": "^4.1.18"
```

The Vite configuration contains the Tailwind plugin:

```plaintext
import { defineConfig } from "vite";
import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [
    react(),
    tailwindcss(),
  ],
});
```

The important part is:

```plaintext
tailwindcss()
```

This tells Vite to process Tailwind CSS as part of the application's build process.

The relationship looks like:

```plaintext
Vite
 │
 ├── React plugin
 │
 └── Tailwind Vite plugin
          │
          ↓
     styles.css
          │
          ↓
    Tailwind CSS v4
```

* * *

**Where Is the Actual Tailwind Theme Configuration?**

This is where the shadcn setup becomes interesting.

The `src/styles.css` file contains Tailwind and shadcn theme configuration.

For example:

```plaintext
@import "tailwindcss";
@import "tw-animate-css";
```

shadcn also defines design tokens using CSS variables:

```plaintext
:root {
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);

  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);

  --border: oklch(0.922 0 0);
}
```

Then those variables are exposed to Tailwind through `@theme`:

```plaintext
@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);

  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);

  --color-border: var(--border);
}
```

So in Tailwind v4, the CSS file is doing much more than simply importing Tailwind. It can also define the application's theme and design tokens.

* * *

**What Does** `@theme` **Do?**

Consider:

```plaintext
@theme inline {
  --color-primary: var(--primary);
}
```

This tells Tailwind that `primary` should be available as a theme color.

We can then use:

```plaintext
<button className="bg-primary text-primary-foreground">
  Login
</button>
```

The relationship is:

```plaintext
CSS variable
     ↓
@theme
     ↓
Tailwind theme token
     ↓
Tailwind utility
     ↓
bg-primary
```

This allows the application to use semantic names such as:

```plaintext
primary
background
foreground
border
```

instead of hard-coding colors throughout every component.

* * *

**What Are** `--background` **and** `--primary`**?**

Variables such as:

```plaintext
--background
--foreground
--primary
```

are **CSS custom properties**.

For example:

```plaintext
:root {
  --background: white;
  --foreground: black;
}
```

We then connect them to Tailwind:

```plaintext
@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
}
```

Now a component can use:

```plaintext
<div className="bg-background text-foreground">
  Hello
</div>
```

Instead of directly writing:

```plaintext
<div className="bg-white text-black">
```

This gives us semantic design tokens that can change depending on the active theme.

* * *

**What Is** `components.json`**?**

The `components.json` file is **shadcn configuration**, not Tailwind configuration.

The initialization command creates this file so that shadcn knows how the project is structured.

It contains information such as:

```plaintext
{
  "style": "new-york",
  "rsc": false,
  "tsx": true,
  "tailwind": {
    "css": "src/styles.css"
  },
  "aliases": {
    "components": "#/components",
    "utils": "#/lib/utils"
  }
}
```

The exact values depend on the preset and template being used.

The easiest way to think about it is:

```plaintext
components.json
       ↓
  shadcn configuration
```

while:

```plaintext
styles.css
       ↓
Tailwind CSS + theme configuration
```

So these two files have different responsibilities.

* * *

**What Is** `src/lib/utils.ts`**?**

shadcn also creates:

```plaintext
src/lib/utils.ts
```

This file contains the `cn()` utility commonly used by shadcn components.

A typical implementation looks like:

```plaintext
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}
```

The purpose of `cn()` is to make it easier to combine conditional and Tailwind classes.

For example:

```plaintext
<Button
  className={cn(
    "bg-primary",
    someCondition && "bg-red-500"
  )}
>
  Login
</Button>
```

Here:

*   `clsx` handles conditional class names.
    
*   `tailwind-merge` resolves conflicting Tailwind utility classes.
    

So instead of manually constructing class strings, components can use:

```plaintext
cn(...)
```

to combine them safely.

* * *

### Step5: Adding Dark Mode with shadcn/ui

To add dark mode to the CodeLens AI frontend, I followed the official **shadcn/ui guide for TanStack Start**.

The guide covers the complete setup, including:

*   Creating the `ThemeProvider`
    
*   Using `ScriptOnce` to handle the theme before React hydration
    
*   Wrapping the root layout with `ThemeProvider`
    
*   Adding `suppressHydrationWarning` to the `<html>` element
    
*   Creating the light/dark/system mode toggle
    

This approach is specifically designed for **TanStack Start** and handles the SSR and hydration considerations involved with theme switching.

**Setup guide:**  
[shadcn/ui — Dark Mode for TanStack Start](https://ui.shadcn.com/docs/dark-mode/tanstack-start?utm_source=chatgpt.com)

I followed this guide rather than implementing a separate dark-mode architecture from scratch.

* * *

### Step6: Issue I Faced: TanStack Version Compatibility

While setting up dark mode in my TanStack Start application, I encountered a **500 Internal Server Error during SSR**.

Initially, I suspected that the issue was related to the dark-mode implementation. However, after debugging, I found that the problem was caused by an **incompatible combination of TanStack package versions**.

I had initially used `latest` for the TanStack packages. Since TanStack Start depends on several closely related TanStack packages, using mismatched versions can lead to unexpected issues during server-side rendering.

The problem looked roughly like this:

```plaintext
TanStack Start
      ↓
TanStack packages
      ↓
Incompatible versions
      ↓
SSR failure
      ↓
500 Internal Server Error
```

* * *

**How I Fixed It**

I pinned the TanStack packages to compatible versions instead of using `latest`.

```plaintext
Before

TanStack packages
      ↓
latest versions
      ↓
Version mismatch
      ↓
SSR 500 error
```

After pinning compatible versions:

```plaintext
TanStack packages
      ↓
Compatible versions
      ↓
SSR works correctly
      ↓
Application loads normally
```

After making this change, the **500 SSR error was resolved**.

* * *

**What I Learned**

This was a useful lesson about dependency management in framework ecosystems.

When a framework is composed of multiple closely related packages, using `latest` for every package does not necessarily guarantee that all of them are compatible with each other.

So when debugging an SSR error, it is worth checking:

```plaintext
Application code
      ↓
Framework configuration
      ↓
Package versions
      ↓
SSR / hydration
```

In my case, the issue was not the dark-mode implementation itself. The problem was the **TanStack package version combination**.

For the dark-mode implementation itself, I followed the official [shadcn/ui TanStack Start dark mode guide](https://ui.shadcn.com/docs/dark-mode/tanstack-start), which specifically covers the SSR/hydration considerations for TanStack Start.

* * *

### Step7: Setting Up TanStack Query

After setting up TanStack Start and the UI foundation, I configured **TanStack Query** to manage server state in the frontend.

* * *

**Installing TanStack Query**

I installed TanStack Query using:

```plaintext
pnpm add @tanstack/react-query
```

This added the `@tanstack/react-query` package to the project.

* * *

**Creating the** `QueryClient`

The next step was configuring TanStack Query in `router.tsx`.

I imported:

```plaintext
import {
  QueryClient,
  QueryClientProvider,
} from "@tanstack/react-query";
```

Then I created a `QueryClient`:

```plaintext
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      refetchOnWindowFocus: false,
      staleTime: 1000 * 60 * 5,
    },
  },
});
```

**What is** `QueryClient`**?**

`QueryClient` is the main manager of TanStack Query.

It is responsible for things such as:

*   Caching API data
    
*   Managing API requests
    
*   Managing stale data
    
*   Controlling refetching
    
*   Managing query state
    

Conceptually:

```plaintext
API / Server
     ↓
QueryClient
     ↓
Query Cache
     ↓
React Components
```

* * *

**Configuring** `QueryClientProvider`

Creating a `QueryClient` alone isn't enough.

React components need access to that client. For this, TanStack Query provides `QueryClientProvider`.

I wrapped the components rendered by TanStack Router inside the provider:

```plaintext
Wrap: ({ children }) => (
  <QueryClientProvider client={queryClient}>
    {children}
  </QueryClientProvider>
),
```

The relevant part of `router.tsx` therefore looks like:

```plaintext
export function getRouter() {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        refetchOnWindowFocus: false,
        staleTime: 1000 * 60 * 5,
      },
    },
  });

  const router = createTanStackRouter({
    routeTree,
    scrollRestoration: true,
    defaultPreload: "intent",
    defaultPreloadStaleTime: 0,

    Wrap: ({ children }) => (
      <QueryClientProvider client={queryClient}>
        {children}
      </QueryClientProvider>
    ),
  });

  return router;
}
```

**Why** `Wrap`**?**

TanStack Router's `Wrap` allows us to wrap the router-rendered application with another React component.

In this case:

```plaintext
TanStack Router
      ↓
Wrap
      ↓
QueryClientProvider
      ↓
Route Components
```

Therefore, components rendered inside the router have access to the `QueryClient`.

This means that inside any route or component, I can use:

```plaintext
useQuery(...)
```

because the component is rendered inside:

```plaintext
<QueryClientProvider>
```

* * *

**How the Data Flow Works Now**

The relationship between these pieces is:

```plaintext
User opens application
        ↓
TanStack Router
        ↓
Route Component
        ↓
useQuery()
        ↓
QueryClient
        ↓
API
        ↓
QueryClient Cache
        ↓
Component receives data
```
