> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ooneex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Routing

> Client-side routing in the Single Page App with file-based TanStack Router.

The Single Page App routes with **file-based [TanStack Router](https://tanstack.com/router)**. Every route is a file in `src/routes/`: its location on disk maps to a URL path, and the tooling compiles those files into `src/bootstrap/routeTree.gen.ts` — the generated route tree the router consumes at runtime. You write small, declarative route files; the framework wires up the tree, type-safe navigation, and matching for you.

Routes stay thin. A route file is about wiring — it points a URL at a component and a set of boundaries (pending, error, not-found) and nothing more. The actual UI lives in [features](/spa/features) and data fetching lives in [hooks](/spa/data-fetching), so each route reads as a clear map from path to behavior.

## How it works

A route file declares a `Route` with `createFileRoute`. The path string mirrors the file's location under `src/routes/`. The build step scans `src/routes/`, assembles every route into `routeTree.gen.ts`, and the router (mounted in `src/bootstrap/app.tsx`) uses that tree to match the current URL and render the matching component — or one of its boundaries while the route loads, errors, or fails to match.

| Concept        | What happens                                                                                                                                     |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| File → URL     | A file at `src/routes/<kebab>.tsx` maps to the URL `/<kebab>`. The path you pass to `createFileRoute` matches that location.                     |
| Root route     | `src/routes/__root.tsx` is the app-wide layout and the error / not-found boundaries that wrap every page.                                        |
| Index route    | `src/routes/index.tsx` is the index (`/`) route — the landing page.                                                                              |
| Generated tree | All route files are compiled into `src/bootstrap/routeTree.gen.ts`. This is tooling output — never edit it by hand.                              |
| Boundaries     | Each route can declare `pendingComponent`, `errorComponent`, and `notFoundComponent` so loading, failure, and missing states render predictably. |
| Nesting        | A layout renders its child routes through `<Outlet />` from `@tanstack/react-router`.                                                            |
| Mounting       | The router and React root are created and mounted in `src/bootstrap/app.tsx`, where global providers (e.g. the TanStack Query client) are wired. |

<Warning>
  Never edit `src/bootstrap/routeTree.gen.ts` by hand. It is generated from the files in `src/routes/` and is Biome-ignored — any manual change is overwritten the next time the tree is regenerated. To change routing, add, rename, or remove files in `src/routes/`.
</Warning>

## The root route

`src/routes/__root.tsx` is the entry of the tree. It defines the layout that wraps every page — shared chrome (navigation, providers-aware structure) plus the app-wide error and not-found boundaries. Every other route renders inside it, so put cross-page concerns here rather than repeating them per route.

## The index route

`src/routes/index.tsx` is the index route for `/` — the landing page rendered when no deeper path matches. It is an ordinary route file: a `Route` declared with `createFileRoute` that points at the landing component.

## Defining a route

Create a feature route with `spa:feature:create`. It generates a file at `src/routes/<kebab>.tsx` that maps to `/<kebab>`, declares the `Route` with `createFileRoute`, and wires a component alongside its pending, error, and not-found boundary components. A real generated route:

```tsx theme={null}
import { createFileRoute } from "@tanstack/react-router";
import { SettingsErrorLayout } from "../features/settings/layouts/SettingsErrorLayout";
import { SettingsLayout } from "../features/settings/layouts/SettingsLayout";
import { SettingsNotFoundLayout } from "../features/settings/layouts/SettingsNotFoundLayout";
import { SettingsSkeletonLayout } from "../features/settings/layouts/SettingsSkeletonLayout";

export const Route = createFileRoute("/settings")({
  component: SettingsLayout,
  pendingComponent: SettingsSkeletonLayout,
  errorComponent: SettingsErrorLayout,
  notFoundComponent: SettingsNotFoundLayout,
});
```

Each option maps to a state the router renders:

* `component` — the page rendered when the route matches and is ready.
* `pendingComponent` — shown while the route resolves (e.g. a skeleton).
* `errorComponent` — shown when the route throws.
* `notFoundComponent` — shown when no matching child is found.

The components come from the route's feature — the route file only references them, keeping the wiring separate from the UI.

## Nesting with Outlet

A layout renders its child routes through `<Outlet />` from `@tanstack/react-router`. Place `Outlet` where children should appear, and the matched child route renders into that slot:

```tsx theme={null}
import { Outlet } from "@tanstack/react-router";

export const SettingsLayout = ({ children }: { children?: React.ReactNode }) => {
  return <section>{children ?? <Outlet />}</section>;
};
```

This is how a parent route wraps its children with shared structure while each child controls its own content.

## Mounting the router

The router and the React root are created and mounted in `src/bootstrap/app.tsx`. The router is built from the generated `routeTree.gen.ts`, and global providers — such as the TanStack Query client — are wired around it there. That single file is the boundary between the generated route tree and the running app: add app-wide providers here, not in individual routes.

## Reading query params

Navigation and links come from `@tanstack/react-router`. To read the current URL's search parameters, use the `useSearch` hook. The spa's `useLang` hook reads the `lang` query param from any route:

```tsx theme={null}
import { useSearch } from "@tanstack/react-router";

export const DEFAULT_LANG = "en";

// strict: false opts out of route-specific search typing so it works from any route.
export const useLang = (): string => {
  const search = useSearch({ strict: false }) as { lang?: string };
  return search.lang ?? DEFAULT_LANG;
};
```

Passing `strict: false` opts out of route-specific search typing, so the hook works regardless of which route the component is mounted under — useful for cross-cutting values like the active language (see [internationalization](/spa/internationalization)). Route params follow the same idea: read them through the router's hooks rather than parsing the URL yourself.

## Best practices

* **Keep routes thin.** A route file should wire a component and its boundaries — nothing more. Push UI into [features](/spa/features) and data fetching into [hooks](/spa/data-fetching).
* **Never edit `routeTree.gen.ts`.** It is generated from `src/routes/` and Biome-ignored. Change routing by editing files in `src/routes/`, then let the tree regenerate.
* **Put backend calls in hooks.** Routes wire; hooks fetch. Keep data access out of route files so they stay declarative — see [data fetching](/spa/data-fetching).
* **Use the boundaries.** Declare `pendingComponent`, `errorComponent`, and `notFoundComponent` so loading, failure, and missing states are explicit instead of blank screens.
* **Centralize app-wide concerns.** Put shared layout and boundaries in `__root.tsx`, and global providers in `bootstrap/app.tsx`, rather than repeating them per route.
* **Read params through router hooks.** Use `useSearch` (and the router's param hooks) instead of reading `window.location` directly, so values stay in sync with navigation.

## Related

* [SPA overview](/spa/overview) — what the Single Page App is and how it fits together.
* [Structure](/spa/structure) — where `routes/`, `features/`, and `bootstrap/` live.
* [Features](/spa/features) — the components and layouts a route delegates to.
* [Data fetching](/spa/data-fetching) — the hooks that load data for a route.
* [Internationalization](/spa/internationalization) — the `useLang` hook and language handling.
* [Backend routing](/basics/routing) — server-side routing, distinct from this client-side router.
