@tanstack/react-router 1.144.0 → 1.145.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- declare const _default: "# Authenticated Routes\n\nAuthentication is an extremely common requirement for web applications. In this guide, we'll walk through how to use TanStack Router to build protected routes, and how to redirect users to login if they try to access them.\n\n## The `route.beforeLoad` Option\n\nThe `route.beforeLoad` option allows you to specify a function that will be called before a route is loaded. It receives all of the same arguments that the `route.loader` function does. This is a great place to check if a user is authenticated, and redirect them to a login page if they are not.\n\nThe `beforeLoad` function runs in relative order to these other route loading functions:\n\n- Route Matching (Top-Down)\n - `route.params.parse`\n - `route.validateSearch`\n- Route Loading (including Preloading)\n - **`route.beforeLoad`**\n - `route.onError`\n- Route Loading (Parallel)\n - `route.component.preload?`\n - `route.load`\n\n**It's important to know that the `beforeLoad` function for a route is called _before any of its child routes' `beforeLoad` functions_.** It is essentially a middleware function for the route and all of its children.\n\n**If you throw an error in `beforeLoad`, none of its children will attempt to load**.\n\n## Redirecting\n\nWhile not required, some authentication flows require redirecting to a login page. To do this, you can **throw a `redirect()`** from `beforeLoad`:\n\n```tsx\n// src/routes/_authenticated.tsx\nexport const Route = createFileRoute('/_authenticated')({\n beforeLoad: async ({ location }) => {\n if (!isAuthenticated()) {\n throw redirect({\n to: '/login',\n search: {\n // Use the current location to power a redirect after login\n // (Do not use `router.state.resolvedLocation` as it can\n // potentially lag behind the actual current location)\n redirect: location.href,\n },\n })\n }\n },\n})\n```\n\n> [!TIP]\n> The `redirect()` function takes all of the same options as the `navigate` function, so you can pass options like `replace: true` if you want to replace the current history entry instead of adding a new one.\n\nOnce you have authenticated a user, it's also common practice to redirect them back to the page they were trying to access. To do this, you can utilize the `redirect` search param that we added in our original redirect. Since we'll be replacing the entire URL with what it was, `router.history.push` is better suited for this than `router.navigate`:\n\n```tsx\nrouter.history.push(search.redirect)\n```\n\n## Non-Redirected Authentication\n\nSome applications choose to not redirect users to a login page, and instead keep the user on the same page and show a login form that either replaces the main content or hides it via a modal. This is also possible with TanStack Router by simply short circuiting rendering the `<Outlet />` that would normally render the child routes:\n\n```tsx\n// src/routes/_authenticated.tsx\nexport const Route = createFileRoute('/_authenticated')({\n component: () => {\n if (!isAuthenticated()) {\n return <Login />\n }\n\n return <Outlet />\n },\n})\n```\n\nThis keeps the user on the same page, but still allows you to render a login form. Once the user is authenticated, you can simply render the `<Outlet />` and the child routes will be rendered.\n\n## Authentication using React context/hooks\n\nIf your authentication flow relies on interactions with React context and/or hooks, you'll need to pass down your authentication state to TanStack Router using `router.context` option.\n\n> [!IMPORTANT]\n> React hooks are not meant to be consumed outside of React components. If you need to use a hook outside of a React component, you need to extract the returned state from the hook in a component that wraps your `<RouterProvider />` and then pass the returned value down to TanStack Router.\n\nWe'll cover the `router.context` options in-detail in the [Router Context](./router-context.md) section.\n\nHere's an example that uses React context and hooks for protecting authenticated routes in TanStack Router. See the entire working setup in the [Authenticated Routes example](https://github.com/TanStack/router/tree/main/examples/react/authenticated-routes).\n\n- `src/routes/__root.tsx`\n\n```tsx\nimport { createRootRouteWithContext } from '@tanstack/react-router'\n\ninterface MyRouterContext {\n // The ReturnType of your useAuth hook or the value of your AuthContext\n auth: AuthState\n}\n\nexport const Route = createRootRouteWithContext<MyRouterContext>()({\n component: () => <Outlet />,\n})\n```\n\n- `src/router.tsx`\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nimport { routeTree } from './routeTree.gen'\n\nexport const router = createRouter({\n routeTree,\n context: {\n // auth will initially be undefined\n // We'll be passing down the auth state from within a React component\n auth: undefined!,\n },\n})\n```\n\n- `src/App.tsx`\n\n```tsx\nimport { RouterProvider } from '@tanstack/react-router'\n\nimport { AuthProvider, useAuth } from './auth'\n\nimport { router } from './router'\n\nfunction InnerApp() {\n const auth = useAuth()\n return <RouterProvider router={router} context={{ auth }} />\n}\n\nfunction App() {\n return (\n <AuthProvider>\n <InnerApp />\n </AuthProvider>\n )\n}\n```\n\nThen in the authenticated route, you can check the auth state using the `beforeLoad` function, and **throw a `redirect()`** to your **Login route** if the user is not signed-in.\n\n- `src/routes/dashboard.route.tsx`\n\n```tsx\nimport { createFileRoute, redirect } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/dashboard')({\n beforeLoad: ({ context, location }) => {\n if (!context.auth.isAuthenticated) {\n throw redirect({\n to: '/login',\n search: {\n redirect: location.href,\n },\n })\n }\n },\n})\n```\n\nYou can _optionally_, also use the [Non-Redirected Authentication](#non-redirected-authentication) approach to show a login form instead of calling a **redirect**.\n\nThis approach can also be used in conjunction with Pathless or Layout Route to protect all routes under their parent route.\n\n## Related How-To Guides\n\nFor detailed, step-by-step implementation guides, see:\n\n- [How to Set Up Basic Authentication](../how-to/setup-authentication.md) - Complete setup with React Context and protected routes\n- [How to Integrate Authentication Providers](../how-to/setup-auth-providers.md) - Use Auth0, Clerk, or Supabase\n- [How to Set Up Role-Based Access Control](../how-to/setup-rbac.md) - Implement permissions and role-based routing\n\n## Examples\n\nWorking authentication examples are available in the repository:\n\n- [Basic Authentication Example](https://github.com/TanStack/router/tree/main/examples/react/authenticated-routes) - Simple authentication with context\n- [Firebase Authentication](https://github.com/TanStack/router/tree/main/examples/react/authenticated-routes-firebase) - Firebase Auth integration\n- [TanStack Start Auth Examples](https://github.com/TanStack/router/tree/main/examples/react) - Various auth implementations with TanStack Start\n\n# Automatic Code Splitting\n\nThe automatic code splitting feature in TanStack Router allows you to optimize your application's bundle size by lazily loading route components and their associated data. This is particularly useful for large applications where you want to minimize the initial load time by only loading the necessary code for the current route.\n\nTo turn this feature on, simply set the `autoCodeSplitting` option to `true` in your bundler plugin configuration. This enables the router to automatically handle code splitting for your routes without requiring any additional setup.\n\n```ts\n// vite.config.ts\nimport { defineConfig } from 'vite'\nimport { tanstackRouter } from '@tanstack/router-plugin/vite'\n\nexport default defineConfig({\n plugins: [\n tanstackRouter({\n autoCodeSplitting: true, // Enable automatic code splitting\n }),\n ],\n})\n```\n\nBut that's just the beginning! TanStack Router's automatic code splitting is not only easy to enable, but it also provides powerful customization options to tailor how your routes are split into chunks. This allows you to optimize your application's performance based on your specific needs and usage patterns.\n\n## How does it work?\n\nTanStack Router's automatic code splitting works by transforming your route files both during 'development' and at 'build' time. It rewrites the route definitions to use lazy-loading wrappers for components and loaders, which allows the bundler to group these properties into separate chunks.\n\n> [!TIP]\n> A **chunk** is a file that contains a portion of your application's code, which can be loaded on demand. This helps reduce the initial load time of your application by only loading the code that is needed for the current route.\n\nSo when your application loads, it doesn't include all the code for every route. Instead, it only includes the code for the routes that are initially needed. As users navigate through your application, additional chunks are loaded on demand.\n\nThis happens seamlessly, without requiring you to manually split your code or manage lazy loading. The TanStack Router bundler plugin takes care of everything, ensuring that your routes are optimized for performance right out of the box.\n\n### The transformation process\n\nWhen you enable automatic code splitting, the bundler plugin does this by using static code analysis look at your the code in your route files to transform them into optimized outputs.\n\nThis transformation process produces two key outputs when each of your route files are processed:\n\n1. **Reference File**: The bundler plugin takes your original route file (e.g., `posts.route.tsx`) and modifies the values for properties like `component` or `pendingComponent` to use special lazy-loading wrappers that'll fetch the actual code later. These wrappers point to a \"virtual\" file that the bundler will resolve later on.\n2. **Virtual File**: When the bundler sees a request for one of these virtual files (e.g., `posts.route.tsx?tsr-split=component`), it intercepts it to generate a new, minimal on-the-fly file that _only_ contains the code for the requested properties (e.g., just the `PostsComponent`).\n\nThis process ensures that your original code remains clean and readable, while the actual bundled output is optimized for initial bundle size.\n\n### What gets code split?\n\nThe decision of what to split into separate chunks is crucial for optimizing your application's performance. TanStack Router uses a concept called \"**Split Groupings**\" to determine how different parts of your route should be bundled together.\n\nSplit groupings are arrays of properties that tell TanStack Router how to bundle different parts of your route together. Each grouping is an list of property names that you want to bundle together into a single lazy-loaded chunk.\n\nThe available properties to split are:\n\n- `component`\n- `errorComponent`\n- `pendingComponent`\n- `notFoundComponent`\n- `loader`\n\nBy default, TanStack Router uses the following split groupings:\n\n```sh\n[\n ['component'],\n ['errorComponent'],\n ['notFoundComponent']\n]\n```\n\nThis means that it creates three separate lazy-loaded chunks for each route. Resulting in:\n\n- One for the main component\n- One for the error component\n- And one for the not-found component.\n\n### Rules of Splitting\n\nFor automatic code splitting to work, there are some rules in-place to make sure that this process can reliably and predictably happen.\n\n#### Do not export route properties\n\nRoute properties like `component`, `loader`, etc., should not be exported from the route file. Exporting these properties results in them being bundled into the main application bundle, which means that they will not be code-split.\n\n```tsx\nimport { createRoute } from '@tanstack/react-router'\n\nexport const Route = createRoute('/posts')({\n // ...\n notFoundComponent: PostsNotFoundComponent,\n})\n\n// \u274C Do NOT do this!\n// Exporting the notFoundComponent will prevent it from being code-split\n// and will be included in the main bundle.\nexport function PostsNotFoundComponent() {\n // \u274C\n // ...\n}\n\nfunction PostsNotFoundComponent() {\n // \u2705\n // ...\n}\n```\n\n**That's it!** There are no other restrictions. You can use any other JavaScript or TypeScript features in your route files as you normally would. If you run into any issues, please [open an issue](https://github.com/tanstack/router/issues) on GitHub.\n\n## Granular control\n\nFor most applications, the default behavior of using `autoCodeSplitting: true` is sufficient. However, TanStack Router provides several options to customize how your routes are split into chunks, allowing you to optimize for specific use cases or performance needs.\n\n### Global code splitting behavior (`defaultBehavior`)\n\nYou can change how TanStack Router splits your routes by changing the `defaultBehavior` option in your bundler plugin configuration. This allows you to define how different properties of your routes should be bundled together.\n\nFor example, to bundle all UI-related components into a single chunk, you could configure it like this:\n\n```ts\n// vite.config.ts\nimport { defineConfig } from 'vite'\nimport { tanstackRouter } from '@tanstack/router-plugin/vite'\n\nexport default defineConfig({\n plugins: [\n tanstackRouter({\n autoCodeSplitting: true,\n codeSplittingOptions: {\n defaultBehavior: [\n [\n 'component',\n 'pendingComponent',\n 'errorComponent',\n 'notFoundComponent',\n ], // Bundle all UI components together\n ],\n },\n }),\n ],\n})\n```\n\n### Advanced programmatic control (`splitBehavior`)\n\nFor complex rulesets, you can use the `splitBehavior` function in your vite config to programmatically define how routes should be split into chunks based on their `routeId`. This function allows you to implement custom logic for grouping properties together, giving you fine-grained control over the code splitting behavior.\n\n```ts\n// vite.config.ts\nimport { defineConfig } from 'vite'\nimport { tanstackRouter } from '@tanstack/router-plugin/vite'\n\nexport default defineConfig({\n plugins: [\n tanstackRouter({\n autoCodeSplitting: true,\n codeSplittingOptions: {\n splitBehavior: ({ routeId }) => {\n // For all routes under /posts, bundle the loader and component together\n if (routeId.startsWith('/posts')) {\n return [['loader', 'component']]\n }\n // All other routes will use the `defaultBehavior`\n },\n },\n }),\n ],\n})\n```\n\n### Per-route overrides (`codeSplitGroupings`)\n\nFor ultimate control, you can override the global configuration directly inside a route file by adding a `codeSplitGroupings` property. This is useful for routes that have unique optimization needs.\n\n```tsx\n// src/routes/posts.route.tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { loadPostsData } from './-heavy-posts-utils'\n\nexport const Route = createFileRoute('/posts')({\n // For this specific route, bundle the loader and component together.\n codeSplitGroupings: [['loader', 'component']],\n loader: () => loadPostsData(),\n component: PostsComponent,\n})\n\nfunction PostsComponent() {\n // ...\n}\n```\n\nThis will create a single chunk that includes both the `loader` and the `component` for this specific route, overriding both the default behavior and any programmatic split behavior defined in your bundler config.\n\n### Configuration order matters\n\nThis guide has so far describe three different ways to configure how TanStack Router splits your routes into chunks.\n\nTo make sure that the different configurations do not conflict with each other, TanStack Router uses the following order of precedence:\n\n1. **Per-route overrides**: The `codeSplitGroupings` property inside a route file takes the highest precedence. This allows you to define specific split groupings for individual routes.\n2. **Programmatic split behavior**: The `splitBehavior` function in your bundler config allows you to define custom logic for how routes should be split based on their `routeId`.\n3. **Default behavior**: The `defaultBehavior` option in your bundler config serves as the fallback for any routes that do not have specific overrides or custom logic defined. This is the base configuration that applies to all routes unless overridden.\n\n### Splitting the Data Loader\n\nThe `loader` function is responsible for fetching data needed by the route. By default, it is bundled with into your \"reference file\" and loaded in the initial bundle. However, you can also split the `loader` into its own chunk if you want to optimize further.\n\n> [!CAUTION]\n> Moving the `loader` into its own chunk is a **performance trade-off**. It introduces an additional trip to the server before the data can be fetched, which can lead to slower initial page loads. This is because the `loader` **must** be fetched and executed before the route can render its component.\n> Therefore, we recommend keeping the `loader` in the initial bundle unless you have a specific reason to split it.\n\n```ts\n// vite.config.ts\nimport { defineConfig } from 'vite'\nimport { tanstackRouter } from '@tanstack/router-plugin/vite'\n\nexport default defineConfig({\n plugins: [\n tanstackRouter({\n autoCodeSplitting: true,\n codeSplittingOptions: {\n defaultBehavior: [\n ['loader'], // The loader will be in its own chunk\n ['component'],\n // ... other component groupings\n ],\n },\n }),\n ],\n})\n```\n\nWe highly discourage splitting the `loader` unless you have a specific use case that requires it. In most cases, not splitting off the `loader` and keep it in the main bundle is the best choice for performance.\n\n# Code Splitting\n\nCode splitting and lazy loading is a powerful technique for improving the bundle size and load performance of an application.\n\n- Reduces the amount of code that needs to be loaded on initial page load\n- Code is loaded on-demand when it is needed\n- Results in more chunks that are smaller in size that can be cached more easily by the browser.\n\n## How does TanStack Router split code?\n\nTanStack Router separates code into two categories:\n\n- **Critical Route Configuration** - The code that is required to render the current route and kick off the data loading process as early as possible.\n - Path Parsing/Serialization\n - Search Param Validation\n - Loaders, Before Load\n - Route Context\n - Static Data\n - Links\n - Scripts\n - Styles\n - All other route configuration not listed below\n\n- **Non-Critical/Lazy Route Configuration** - The code that is not required to match the route, and can be loaded on-demand.\n - Route Component\n - Error Component\n - Pending Component\n - Not-found Component\n\n> \uD83E\uDDE0 **Why is the loader not split?**\n>\n> - The loader is already an asynchronous boundary, so you pay double to both get the chunk _and_ wait for the loader to execute.\n> - Categorically, it is less likely to contribute to a large bundle size than a component.\n> - The loader is one of the most important preloadable assets for a route, especially if you're using a default preload intent, like hovering over a link, so it's important for the loader to be available without any additional async overhead.\n>\n> Knowing the disadvantages of splitting the loader, if you still want to go ahead with it, head over to the [Data Loader Splitting](#data-loader-splitting) section.\n\n## Encapsulating a route's files into a directory\n\nSince TanStack Router's file-based routing system is designed to support both flat and nested file structures, it's possible to encapsulate a route's files into a single directory without any additional configuration.\n\nTo encapsulate a route's files into a directory, move the route file itself into a `.route` file within a directory with the same name as the route file.\n\nFor example, if you have a route file named `posts.tsx`, you would create a new directory named `posts` and move the `posts.tsx` file into that directory, renaming it to `route.tsx`.\n\n**Before**\n\n- `posts.tsx`\n\n**After**\n\n- `posts`\n - `route.tsx`\n\n## Approaches to code splitting\n\nTanStack Router supports multiple approaches to code splitting. If you are using code-based routing, skip to the [Code-Based Splitting](#code-based-splitting) section.\n\nWhen you are using file-based routing, you can use the following approaches to code splitting:\n\n- [Using automatic code-splitting \u2728](#using-automatic-code-splitting)\n- [Using the `.lazy.tsx` suffix](#using-the-lazytsx-suffix)\n- [Using Virtual Routes](#using-virtual-routes)\n\n## Using automatic code-splitting\u2728\n\nThis is the easiest and most powerful way to code split your route files.\n\nWhen using the `autoCodeSplitting` feature, TanStack Router will automatically code split your route files based on the non-critical route configuration mentioned above.\n\n> [!IMPORTANT]\n> The automatic code-splitting feature is **ONLY** available when you are using file-based routing with one of our [supported bundlers](../routing/file-based-routing.md#getting-started-with-file-based-routing).\n> This will **NOT** work if you are **only** using the CLI (`@tanstack/router-cli`).\n\nTo enable automatic code-splitting, you just need to add the following to the configuration of your TanStack Router Bundler Plugin:\n\n```ts\n// vite.config.ts\nimport { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\nimport { tanstackRouter } from '@tanstack/router-plugin/vite'\n\nexport default defineConfig({\n plugins: [\n tanstackRouter({\n // ...\n autoCodeSplitting: true,\n }),\n react(), // Make sure to add this plugin after the TanStack Router Bundler plugin\n ],\n})\n```\n\nThat's it! TanStack Router will automatically code-split all your route files by their critical and non-critical route configurations.\n\nIf you want more control over the code-splitting process, head over to the [Automatic Code Splitting](./automatic-code-splitting.md) guide to learn more about the options available.\n\n## Using the `.lazy.tsx` suffix\n\nIf you are not able to use the automatic code-splitting feature, you can still code-split your route files using the `.lazy.tsx` suffix. It is **as easy as moving your code into a separate file with a `.lazy.tsx` suffix** and using the `createLazyFileRoute` function instead of `createFileRoute`.\n\n> [!IMPORTANT]\n> The `__root.tsx` route file, using either `createRootRoute` or `createRootRouteWithContext`, does not support code splitting, since it's always rendered regardless of the current route.\n\nThese are the only options that `createLazyFileRoute` supports:\n\n| Export Name | Description |\n| ------------------- | --------------------------------------------------------------------- |\n| `component` | The component to render for the route. |\n| `errorComponent` | The component to render when an error occurs while loading the route. |\n| `pendingComponent` | The component to render while the route is loading. |\n| `notFoundComponent` | The component to render if a not-found error gets thrown. |\n\n### Example code splitting with `.lazy.tsx`\n\nWhen you are using `.lazy.tsx` you can split your route into two files to enable code splitting:\n\n**Before (Single File)**\n\n```tsx\n// src/routes/posts.tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { fetchPosts } from './api'\n\nexport const Route = createFileRoute('/posts')({\n loader: fetchPosts,\n component: Posts,\n})\n\nfunction Posts() {\n // ...\n}\n```\n\n**After (Split into two files)**\n\nThis file would contain the critical route configuration:\n\n```tsx\n// src/routes/posts.tsx\n\nimport { createFileRoute } from '@tanstack/react-router'\nimport { fetchPosts } from './api'\n\nexport const Route = createFileRoute('/posts')({\n loader: fetchPosts,\n})\n```\n\nWith the non-critical route configuration going into the file with the `.lazy.tsx` suffix:\n\n```tsx\n// src/routes/posts.lazy.tsx\nimport { createLazyFileRoute } from '@tanstack/react-router'\n\nexport const Route = createLazyFileRoute('/posts')({\n component: Posts,\n})\n\nfunction Posts() {\n // ...\n}\n```\n\n## Using Virtual Routes\n\nYou might run into a situation where you end up splitting out everything from a route file, leaving it empty! In this case, simply **delete the route file entirely**! A virtual route will automatically be generated for you to serve as an anchor for your code split files. This virtual route will live directly in the generated route tree file.\n\n**Before (Virtual Routes)**\n\n```tsx\n// src/routes/posts.tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts')({\n // Hello?\n})\n```\n\n```tsx\n// src/routes/posts.lazy.tsx\nimport { createLazyFileRoute } from '@tanstack/react-router'\n\nexport const Route = createLazyFileRoute('/posts')({\n component: Posts,\n})\n\nfunction Posts() {\n // ...\n}\n```\n\n**After (Virtual Routes)**\n\n```tsx\n// src/routes/posts.lazy.tsx\nimport { createLazyFileRoute } from '@tanstack/react-router'\n\nexport const Route = createLazyFileRoute('/posts')({\n component: Posts,\n})\n\nfunction Posts() {\n // ...\n}\n```\n\nTada! \uD83C\uDF89\n\n## Code-Based Splitting\n\nIf you are using code-based routing, you can still code-split your routes using the `Route.lazy()` method and the `createLazyRoute` function. You'll need to split your route configuration into two parts:\n\nCreate a lazy route using the `createLazyRoute` function.\n\n```tsx\n// src/posts.lazy.tsx\nexport const Route = createLazyRoute('/posts')({\n component: MyComponent,\n})\n\nfunction MyComponent() {\n return <div>My Component</div>\n}\n```\n\nThen, call the `.lazy` method on the route definition in your `app.tsx` to import the lazy/code-split route with the non-critical route configuration.\n\n```tsx\n// src/app.tsx\nconst postsRoute = createRoute({\n getParentRoute: () => rootRoute,\n path: '/posts',\n}).lazy(() => import('./posts.lazy').then((d) => d.Route))\n```\n\n## Data Loader Splitting\n\n**Be warned!!!** Splitting a route loader is a dangerous game.\n\nIt can be a powerful tool to reduce bundle size, but it comes with a cost as mentioned in the [How does TanStack Router split code?](#how-does-tanstack-router-split-code) section.\n\nYou can code split your data loading logic using the Route's `loader` option. While this process makes it difficult to maintain type-safety with the parameters passed to your loader, you can always use the generic `LoaderContext` type to get you most of the way there:\n\n```tsx\nimport { lazyFn } from '@tanstack/react-router'\n\nconst route = createRoute({\n path: '/my-route',\n component: MyComponent,\n loader: lazyFn(() => import('./loader'), 'loader'),\n})\n\n// In another file...a\nexport const loader = async (context: LoaderContext) => {\n /// ...\n}\n```\n\nIf you are using file-based routing, you'll only be able to split your `loader` if you are using [Automatic Code Splitting](#using-automatic-code-splitting) with customized bundling options.\n\n## Manually accessing Route APIs in other files with the `getRouteApi` helper\n\nAs you might have guessed, placing your component code in a separate file than your route can make it difficult to consume the route itself. To help with this, TanStack Router exports a handy `getRouteApi` function that you can use to access a route's type-safe APIs in a file without importing the route itself.\n\n- `my-route.tsx`\n\n```tsx\nimport { createRoute } from '@tanstack/react-router'\nimport { MyComponent } from './MyComponent'\n\nconst route = createRoute({\n path: '/my-route',\n loader: () => ({\n foo: 'bar',\n }),\n component: MyComponent,\n})\n```\n\n- `MyComponent.tsx`\n\n```tsx\nimport { getRouteApi } from '@tanstack/react-router'\n\nconst route = getRouteApi('/my-route')\n\nexport function MyComponent() {\n const loaderData = route.useLoaderData()\n // ^? { foo: string }\n\n return <div>...</div>\n}\n```\n\nThe `getRouteApi` function is useful for accessing other type-safe APIs:\n\n- `useLoaderData`\n- `useLoaderDeps`\n- `useMatch`\n- `useParams`\n- `useRouteContext`\n- `useSearch`\n\n# Creating a Router\n\n## The `Router` Class\n\nWhen you're ready to start using your router, you'll need to create a new `Router` instance. The router instance is the core brains of TanStack Router and is responsible for managing the route tree, matching routes, and coordinating navigations and route transitions. It also serves as a place to configure router-wide settings.\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n // ...\n})\n```\n\n## Route Tree\n\nYou'll probably notice quickly that the `Router` constructor requires a `routeTree` option. This is the route tree that the router will use to match routes and render components.\n\nWhether you used [file-based routing](../routing/file-based-routing.md) or [code-based routing](../routing/code-based-routing.md), you'll need to pass your route tree to the `createRouter` function:\n\n### Filesystem Route Tree\n\nIf you used our recommended file-based routing, then it's likely your generated route tree file was created at the default `src/routeTree.gen.ts` location. If you used a custom location, then you'll need to import your route tree from that location.\n\n```tsx\nimport { routeTree } from './routeTree.gen'\n```\n\n### Code-Based Route Tree\n\nIf you used code-based routing, then you likely created your route tree manually using the root route's `addChildren` method:\n\n```tsx\nconst routeTree = rootRoute.addChildren([\n // ...\n])\n```\n\n## Router Type Safety\n\n> [!IMPORTANT]\n> DO NOT SKIP THIS SECTION! \u26A0\uFE0F\n\nTanStack Router provides amazing support for TypeScript, even for things you wouldn't expect like bare imports straight from the library! To make this possible, you must register your router's types using TypeScripts' [Declaration Merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html) feature. This is done by extending the `Register` interface on `@tanstack/react-router` with a `router` property that has the type of your `router` instance:\n\n```tsx\ndeclare module '@tanstack/react-router' {\n interface Register {\n // This infers the type of our router and registers it across your entire project\n router: typeof router\n }\n}\n```\n\nWith your router registered, you'll now get type-safety across your entire project for anything related to routing.\n\n## 404 Not Found Route\n\nAs promised in earlier guides, we'll now cover the `notFoundRoute` option. This option is used to configure a route that will render when no other suitable match is found. This is useful for rendering a 404 page or redirecting to a default route.\n\nIf you are using either file-based or code-based routing, then you'll need to add a `notFoundComponent` key to `createRootRoute`:\n\n```tsx\nexport const Route = createRootRoute({\n component: () => (\n // ...\n ),\n notFoundComponent: () => <div>404 Not Found</div>,\n});\n```\n\n## Other Options\n\nThere are many other options that can be passed to the `Router` constructor. You can find a full list of them in the [API Reference](../api/router/RouterOptionsType.md).\n\n# Custom Link\n\nWhile repeating yourself can be acceptable in many situations, you might find that you do it too often. At times, you may want to create cross-cutting components with additional behavior or styles. You might also consider using third-party libraries in combination with TanStack Router's type safety.\n\n## `createLink` for cross-cutting concerns\n\n`createLink` creates a custom `Link` component with the same type parameters as `Link`. This means you can create your own component which provides the same type safety and typescript performance as `Link`.\n\n### Basic example\n\nIf you want to create a basic custom link component, you can do so with the following:\n\n[//]: # 'BasicExampleImplementation'\n\n```tsx\nimport * as React from 'react'\nimport { createLink, LinkComponent } from '@tanstack/react-router'\n\ninterface BasicLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n // Add any additional props you want to pass to the anchor element\n}\n\nconst BasicLinkComponent = React.forwardRef<HTMLAnchorElement, BasicLinkProps>(\n (props, ref) => {\n return (\n <a ref={ref} {...props} className={'block px-3 py-2 text-blue-700'} />\n )\n },\n)\n\nconst CreatedLinkComponent = createLink(BasicLinkComponent)\n\nexport const CustomLink: LinkComponent<typeof BasicLinkComponent> = (props) => {\n return <CreatedLinkComponent preload={'intent'} {...props} />\n}\n```\n\n[//]: # 'BasicExampleImplementation'\n\nYou can then use your newly created `Link` component as any other `Link`\n\n```tsx\n<CustomLink to={'/dashboard/invoices/$invoiceId'} params={{ invoiceId: 0 }} />\n```\n\n[//]: # 'ExamplesUsingThirdPartyLibs'\n\n## `createLink` with third party libraries\n\nHere are some examples of how you can use `createLink` with third-party libraries.\n\n### React Aria Components example\n\nReact Aria Components v1.11.0 and later works with TanStack Router's `preload (intent)` prop. Use `createLink` to wrap each React Aria component that you use as a link.\n\n```tsx\nimport { createLink } from '@tanstack/react-router'\nimport { Link as RACLink, MenuItem } from 'react-aria-components'\n\nexport const Link = createLink(RACLink)\nexport const MenuItemLink = createLink(MenuItem)\n```\n\nTo use React Aria's render props, including the `className`, `style`, and `children` functions, create a wrapper component and pass that to `createLink`.\n\n```tsx\nimport { createLink } from '@tanstack/react-router'\nimport { Link as RACLink, type LinkProps } from 'react-aria-components'\n\ninterface MyLinkProps extends LinkProps {\n // your props\n}\n\nfunction MyLink(props: MyLinkProps) {\n return (\n <RACLink\n {...props}\n style={({ isHovered }) => ({\n color: isHovered ? 'red' : 'blue',\n })}\n />\n )\n}\n\nexport const Link = createLink(MyLink)\n```\n\n### Chakra UI example\n\n```tsx\nimport * as React from 'react'\nimport { createLink, LinkComponent } from '@tanstack/react-router'\nimport { Link } from '@chakra-ui/react'\n\ninterface ChakraLinkProps\n extends Omit<React.ComponentPropsWithoutRef<typeof Link>, 'href'> {\n // Add any additional props you want to pass to the link\n}\n\nconst ChakraLinkComponent = React.forwardRef<\n HTMLAnchorElement,\n ChakraLinkProps\n>((props, ref) => {\n return <Link ref={ref} {...props} />\n})\n\nconst CreatedLinkComponent = createLink(ChakraLinkComponent)\n\nexport const CustomLink: LinkComponent<typeof ChakraLinkComponent> = (\n props,\n) => {\n return (\n <CreatedLinkComponent\n textDecoration={'underline'}\n _hover={{ textDecoration: 'none' }}\n _focus={{ textDecoration: 'none' }}\n preload={'intent'}\n {...props}\n />\n )\n}\n```\n\n### MUI example\n\nThere is an [example](https://github.com/TanStack/router/tree/main/examples/react/start-material-ui) available which uses these patterns.\n\n#### `Link`\n\nIf the MUI `Link` should simply behave like the router `Link`, it can be just wrapped with `createLink`:\n\n```tsx\nimport { createLink } from '@tanstack/react-router'\nimport { Link } from '@mui/material'\n\nexport const CustomLink = createLink(Link)\n```\n\nIf the `Link` should be customized this approach can be used:\n\n```tsx\nimport React from 'react'\nimport { createLink } from '@tanstack/react-router'\nimport { Link } from '@mui/material'\nimport type { LinkProps } from '@mui/material'\nimport type { LinkComponent } from '@tanstack/react-router'\n\ninterface MUILinkProps extends LinkProps {\n // Add any additional props you want to pass to the Link\n}\n\nconst MUILinkComponent = React.forwardRef<HTMLAnchorElement, MUILinkProps>(\n (props, ref) => <Link ref={ref} {...props} />,\n)\n\nconst CreatedLinkComponent = createLink(MUILinkComponent)\n\nexport const CustomLink: LinkComponent<typeof MUILinkComponent> = (props) => {\n return <CreatedLinkComponent preload={'intent'} {...props} />\n}\n\n// Can also be styled\n```\n\n#### `Button`\n\nIf a `Button` should be used as a router `Link`, the `component` should be set as `a`:\n\n```tsx\nimport React from 'react'\nimport { createLink } from '@tanstack/react-router'\nimport { Button } from '@mui/material'\nimport type { ButtonProps } from '@mui/material'\nimport type { LinkComponent } from '@tanstack/react-router'\n\ninterface MUIButtonLinkProps extends ButtonProps<'a'> {\n // Add any additional props you want to pass to the Button\n}\n\nconst MUIButtonLinkComponent = React.forwardRef<\n HTMLAnchorElement,\n MUIButtonLinkProps\n>((props, ref) => <Button ref={ref} component=\"a\" {...props} />)\n\nconst CreatedButtonLinkComponent = createLink(MUIButtonLinkComponent)\n\nexport const CustomButtonLink: LinkComponent<typeof MUIButtonLinkComponent> = (\n props,\n) => {\n return <CreatedButtonLinkComponent preload={'intent'} {...props} />\n}\n```\n\n#### Usage with `styled`\n\nAny of these MUI approaches can then be used with `styled`:\n\n```tsx\nimport { css, styled } from '@mui/material'\nimport { CustomLink } from './CustomLink'\n\nconst StyledCustomLink = styled(CustomLink)(\n ({ theme }) => css`\n color: ${theme.palette.common.white};\n `,\n)\n```\n\n### Mantine example\n\n```tsx\nimport * as React from 'react'\nimport { createLink, LinkComponent } from '@tanstack/react-router'\nimport { Anchor, AnchorProps } from '@mantine/core'\n\ninterface MantineAnchorProps extends Omit<AnchorProps, 'href'> {\n // Add any additional props you want to pass to the anchor\n}\n\nconst MantineLinkComponent = React.forwardRef<\n HTMLAnchorElement,\n MantineAnchorProps\n>((props, ref) => {\n return <Anchor ref={ref} {...props} />\n})\n\nconst CreatedLinkComponent = createLink(MantineLinkComponent)\n\nexport const CustomLink: LinkComponent<typeof MantineLinkComponent> = (\n props,\n) => {\n return <CreatedLinkComponent preload=\"intent\" {...props} />\n}\n```\n\n[//]: # 'ExamplesUsingThirdPartyLibs'\n\n# Custom Search Param Serialization\n\nBy default, TanStack Router parses and serializes your URL Search Params automatically using `JSON.stringify` and `JSON.parse`. This process involves escaping and unescaping the search string, which is a common practice for URL search params, in addition to the serialization and deserialization of the search object.\n\nFor instance, using the default configuration, if you have the following search object:\n\n```tsx\nconst search = {\n page: 1,\n sort: 'asc',\n filters: { author: 'tanner', min_words: 800 },\n}\n```\n\nIt would be serialized and escaped into the following search string:\n\n```txt\n?page=1&sort=asc&filters=%7B%22author%22%3A%22tanner%22%2C%22min_words%22%3A800%7D\n```\n\nWe can implement the default behavior with the following code:\n\n```tsx\nimport {\n createRouter,\n parseSearchWith,\n stringifySearchWith,\n} from '@tanstack/react-router'\n\nconst router = createRouter({\n // ...\n parseSearch: parseSearchWith(JSON.parse),\n stringifySearch: stringifySearchWith(JSON.stringify),\n})\n```\n\nHowever, this default behavior may not be suitable for all use cases. For example, you may want to use a different serialization format, such as base64 encoding, or you may want to use a purpose-built serialization/deserialization library, like [query-string](https://github.com/sindresorhus/query-string), [JSURL2](https://github.com/wmertens/jsurl2), or [Zipson](https://jgranstrom.github.io/zipson/).\n\nThis can be achieved by providing your own serialization and deserialization functions to the `parseSearch` and `stringifySearch` options in the [`Router`](../api/router/RouterOptionsType.md#stringifysearch-method) configuration. When doing this, you can utilize TanStack Router's built-in helper functions, `parseSearchWith` and `stringifySearchWith`, to simplify the process.\n\n> [!TIP]\n> An important aspect of serialization and deserialization, is that you are able to get the same object back after deserialization. This is important because if the serialization and deserialization process is not done correctly, you may lose some information. For example, if you are using a library that does not support nested objects, you may lose the nested object when deserializing the search string.\n\n![Diagram showing idempotent nature of URL search param serialization and deserialization](https://raw.githubusercontent.com/TanStack/router/main/docs/router/assets/search-serialization-deserialization-idempotency.jpg)\n\nHere are some examples of how you can customize the search param serialization in TanStack Router:\n\n## Using Base64\n\nIt's common to base64 encode your search params to achieve maximum compatibility across browsers and URL unfurlers, etc. This can be done with the following code:\n\n```tsx\nimport {\n Router,\n parseSearchWith,\n stringifySearchWith,\n} from '@tanstack/react-router'\n\nconst router = createRouter({\n parseSearch: parseSearchWith((value) => JSON.parse(decodeFromBinary(value))),\n stringifySearch: stringifySearchWith((value) =>\n encodeToBinary(JSON.stringify(value)),\n ),\n})\n\nfunction decodeFromBinary(str: string): string {\n return decodeURIComponent(\n Array.prototype.map\n .call(atob(str), function (c) {\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)\n })\n .join(''),\n )\n}\n\nfunction encodeToBinary(str: string): string {\n return btoa(\n encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {\n return String.fromCharCode(parseInt(p1, 16))\n }),\n )\n}\n```\n\n> [\u26A0\uFE0F Why does this snippet not use atob/btoa?](#safe-binary-encodingdecoding)\n\nSo, if we were to turn the previous object into a search string using this configuration, it would look like this:\n\n```txt\n?page=1&sort=asc&filters=eyJhdXRob3IiOiJ0YW5uZXIiLCJtaW5fd29yZHMiOjgwMH0%3D\n```\n\n> [!WARNING]\n> If you are serializing user input into Base64, you run the risk of causing a collision with the URL deserialization. This can lead to unexpected behavior, such as the URL not being parsed correctly or being interpreted as a different value. To avoid this, you should encode the search params using a safe binary encoding/decoding method (see below).\n\n## Using the query-string library\n\nThe [query-string](https://github.com/sindresorhus/query-string) library is a popular for being able to reliably parse and stringify query strings. You can use it to customize the serialization format of your search params. This can be done with the following code:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\nimport qs from 'query-string'\n\nconst router = createRouter({\n // ...\n stringifySearch: stringifySearchWith((value) =>\n qs.stringify(value, {\n // ...options\n }),\n ),\n parseSearch: parseSearchWith((value) =>\n qs.parse(value, {\n // ...options\n }),\n ),\n})\n```\n\nSo, if we were to turn the previous object into a search string using this configuration, it would look like this:\n\n```txt\n?page=1&sort=asc&filters=author%3Dtanner%26min_words%3D800\n```\n\n## Using the JSURL2 library\n\n[JSURL2](https://github.com/wmertens/jsurl2) is a non-standard library that can compress URLs while still maintaining readability. This can be done with the following code:\n\n```tsx\nimport {\n Router,\n parseSearchWith,\n stringifySearchWith,\n} from '@tanstack/react-router'\nimport { parse, stringify } from 'jsurl2'\n\nconst router = createRouter({\n // ...\n parseSearch: parseSearchWith(parse),\n stringifySearch: stringifySearchWith(stringify),\n})\n```\n\nSo, if we were to turn the previous object into a search string using this configuration, it would look like this:\n\n```txt\n?page=1&sort=asc&filters=(author~tanner~min*_words~800)~\n```\n\n## Using the Zipson library\n\n[Zipson](https://jgranstrom.github.io/zipson/) is a very user-friendly and performant JSON compression library (both in runtime performance and the resulting compression performance). To compress your search params with it (which requires escaping/unescaping and base64 encoding/decoding them as well), you can use the following code:\n\n```tsx\nimport {\n Router,\n parseSearchWith,\n stringifySearchWith,\n} from '@tanstack/react-router'\nimport { stringify, parse } from 'zipson'\n\nconst router = createRouter({\n parseSearch: parseSearchWith((value) => parse(decodeFromBinary(value))),\n stringifySearch: stringifySearchWith((value) =>\n encodeToBinary(stringify(value)),\n ),\n})\n\nfunction decodeFromBinary(str: string): string {\n return decodeURIComponent(\n Array.prototype.map\n .call(atob(str), function (c) {\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)\n })\n .join(''),\n )\n}\n\nfunction encodeToBinary(str: string): string {\n return btoa(\n encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {\n return String.fromCharCode(parseInt(p1, 16))\n }),\n )\n}\n```\n\n> [\u26A0\uFE0F Why does this snippet not use atob/btoa?](#safe-binary-encodingdecoding)\n\nSo, if we were to turn the previous object into a search string using this configuration, it would look like this:\n\n```txt\n?page=1&sort=asc&filters=JTdCJUMyJUE4YXV0aG9yJUMyJUE4JUMyJUE4dGFubmVyJUMyJUE4JUMyJUE4bWluX3dvcmRzJUMyJUE4JUMyJUEyQ3UlN0Q%3D\n```\n\n<hr>\n\n### Safe Binary Encoding/Decoding\n\nIn the browser, the `atob` and `btoa` functions are not guaranteed to work properly with non-UTF8 characters. We recommend using these encoding/decoding utilities instead:\n\nTo encode from a string to a binary string:\n\n```typescript\nexport function encodeToBinary(str: string): string {\n return btoa(\n encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {\n return String.fromCharCode(parseInt(p1, 16))\n }),\n )\n}\n```\n\nTo decode from a binary string to a string:\n\n```typescript\nexport function decodeFromBinary(str: string): string {\n return decodeURIComponent(\n Array.prototype.map\n .call(atob(str), function (c) {\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)\n })\n .join(''),\n )\n}\n```\n\n# Data Loading\n\nData loading is a common concern for web applications and is related to routing. When loading a page for your app, it's ideal if all of the page's async requirements are fetched and fulfilled as early as possible, in parallel. The router is the best place to coordinate these async dependencies as it's usually the only place in your app that knows where users are headed before content is rendered.\n\nYou may be familiar with `getServerSideProps` from Next.js or `loader`s from Remix/React-Router. TanStack Router has similar functionality to preload/load assets on a per-route basis in parallel allowing it to render as quickly as possible as it fetches via suspense.\n\nBeyond these normal expectations of a router, TanStack Router goes above and beyond and provides **built-in SWR Caching**, a long-term in-memory caching layer for route loaders. This means that you can use TanStack Router to both preload data for your routes so they load instantaneously or temporarily cache route data for previously visited routes to use again later.\n\n## The route loading lifecycle\n\nEvery time a URL/history update is detected, the router executes the following sequence:\n\n- Route Matching (Top-Down)\n - `route.params.parse`\n - `route.validateSearch`\n- Route Pre-Loading (Serial)\n - `route.beforeLoad`\n - `route.onError`\n - `route.errorComponent` / `parentRoute.errorComponent` / `router.defaultErrorComponent`\n- Route Loading (Parallel)\n - `route.component.preload?`\n - `route.loader`\n - `route.pendingComponent` (Optional)\n - `route.component`\n - `route.onError`\n - `route.errorComponent` / `parentRoute.errorComponent` / `router.defaultErrorComponent`\n\n## To Router Cache or not to Router Cache?\n\nThere is a high possibility that TanStack's router cache will be a good fit for most smaller to medium size applications, but it's important to understand the tradeoffs of using it vs a more robust caching solution like TanStack Query:\n\nTanStack Router Cache Pros:\n\n- Built-in, easy to use, no extra dependencies\n- Handles deduping, preloading, loading, stale-while-revalidate, background refetching on a per-route basis\n- Coarse invalidation (invalidate all routes and cache at once)\n- Automatic garbage collection\n- Works great for apps that share little data between routes\n- \"Just works\" for SSR\n\nTanStack Router Cache Cons:\n\n- No persistence adapters/model\n- No shared caching/deduping between routes\n- No built-in mutation APIs (a basic `useMutation` hook is provided in many examples that may be sufficient for many use cases)\n- No built-in cache-level optimistic update APIs (you can still use ephemeral state from something like a `useMutation` hook to achieve this at the component level)\n\n> [!TIP]\n> If you know right away that you'd like to or need to use something more robust like TanStack Query, skip to the [External Data Loading](./external-data-loading.md) guide.\n\n## Using the Router Cache\n\nThe router cache is built-in and is as easy as returning data from any route's `loader` function. Let's learn how!\n\n## Route `loader`s\n\nRoute `loader` functions are called when a route match is loaded. They are called with a single parameter which is an object containing many helpful properties. We'll go over those in a bit, but first, let's look at an example of a route `loader` function:\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n})\n```\n\n## `loader` Parameters\n\nThe `loader` function receives a single object with the following properties:\n\n- `abortController` - The route's abortController. Its signal is cancelled when the route is unloaded or when the Route is no longer relevant and the current invocation of the `loader` function becomes outdated.\n- `cause` - The cause of the current route match. Can be either one of the following:\n - `enter` - When the route is matched and loaded after not being matched in the previous location.\n - `preload` - When the route is being preloaded.\n - `stay` - When the route is matched and loaded after being matched in the previous location.\n- `context` - The route's context object, which is a merged union of:\n - Parent route context\n - This route's context as provided by the `beforeLoad` option\n- `deps` - The object value returned from the `Route.loaderDeps` function. If `Route.loaderDeps` is not defined, an empty object will be provided instead.\n- `location` - The current location\n- `params` - The route's path params\n- `parentMatchPromise` - `Promise<RouteMatch>` (`undefined` for the root route)\n- `preload` - Boolean which is `true` when the route is being preloaded instead of loaded\n- `route` - The route itself\n\nUsing these parameters, we can do a lot of cool things, but first, let's take a look at how we can control it and when the `loader` function is called.\n\n## Consuming data from `loader`s\n\nTo consume data from a `loader`, use the `useLoaderData` hook defined on your Route object.\n\n```tsx\nconst posts = Route.useLoaderData()\n```\n\nIf you don't have ready access to your route object (i.e. you're deep in the component tree for the current route), you can use `getRouteApi` to access the same hook (as well as the other hooks on the Route object). This should be preferred over importing the Route object, which is likely to create circular dependencies.\n\n```tsx\nimport { getRouteApi } from '@tanstack/react-router'\n\n// in your component\n\nconst routeApi = getRouteApi('/posts')\nconst data = routeApi.useLoaderData()\n```\n\n## Dependency-based Stale-While-Revalidate Caching\n\nTanStack Router provides a built-in Stale-While-Revalidate caching layer for route loaders that is keyed on the dependencies of a route:\n\n- The route's fully parsed pathname\n - e.g. `/posts/1` vs `/posts/2`\n- Any additional dependencies provided by the `loaderDeps` option\n - e.g. `loaderDeps: ({ search: { pageIndex, pageSize } }) => ({ pageIndex, pageSize })`\n\nUsing these dependencies as keys, TanStack Router will cache the data returned from a route's `loader` function and use it to fulfill subsequent requests for the same route match. This means that if a route's data is already in the cache, it will be returned immediately, then **potentially** be refetched in the background depending on the \"freshness\" of the data.\n\n### Key options\n\nTo control router dependencies and \"freshness\", TanStack Router provides a plethora of options to control the keying and caching behavior of your route loaders. Let's take a look at them in the order that you are most likely to use them:\n\n- `routeOptions.loaderDeps`\n - A function that supplies you the search params for a router and returns an object of dependencies for use in your `loader` function. When these deps changed from navigation to navigation, it will cause the route to reload regardless of `staleTime`s. The deps are compared using a deep equality check.\n- `routeOptions.staleTime`\n- `routerOptions.defaultStaleTime`\n - The number of milliseconds that a route's data should be considered fresh when attempting to load.\n- `routeOptions.preloadStaleTime`\n- `routerOptions.defaultPreloadStaleTime`\n - The number of milliseconds that a route's data should be considered fresh attempting to preload.\n- `routeOptions.gcTime`\n- `routerOptions.defaultGcTime`\n - The number of milliseconds that a route's data should be kept in the cache before being garbage collected.\n- `routeOptions.shouldReload`\n - A function that receives the same `beforeLoad` and `loaderContext` parameters and returns a boolean indicating if the route should reload. This offers one more level of control over when a route should reload beyond `staleTime` and `loaderDeps` and can be used to implement patterns similar to Remix's `shouldLoad` option.\n\n### \u26A0\uFE0F Some Important Defaults\n\n- By default, the `staleTime` is set to `0`, meaning that the route's data will always be considered stale and will always be reloaded in the background when the route is rematched.\n- By default, a previously preloaded route is considered fresh for **30 seconds**. This means if a route is preloaded, then preloaded again within 30 seconds, the second preload will be ignored. This prevents unnecessary preloads from happening too frequently. **When a route is loaded normally, the standard `staleTime` is used.**\n- By default, the `gcTime` is set to **30 minutes**, meaning that any route data that has not been accessed in 30 minutes will be garbage collected and removed from the cache.\n- `router.invalidate()` will force all active routes to reload their loaders immediately and mark every cached route's data as stale.\n\n### Using `loaderDeps` to access search params\n\nImagine a `/posts` route supports some pagination via search params `offset` and `limit`. For the cache to uniquely store this data, we need to access these search params via the `loaderDeps` function. By explicitly identifying them, each route match for `/posts` with different `offset` and `limit` won't get mixed up!\n\nOnce we have these deps in place, the route will always reload when the deps change.\n\n```tsx\n// /routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loaderDeps: ({ search: { offset, limit } }) => ({ offset, limit }),\n loader: ({ deps: { offset, limit } }) =>\n fetchPosts({\n offset,\n limit,\n }),\n})\n```\n\n### Using `staleTime` to control how long data is considered fresh\n\nBy default, `staleTime` for navigations is set to `0`ms (and 30 seconds for preloads) which means that the route's data will always be considered stale and will always be reloaded in the background when the route is matched and navigated to.\n\n**This is a good default for most use cases, but you may find that some route data is more static or potentially expensive to load.** In these cases, you can use the `staleTime` option to control how long the route's data is considered fresh for navigations. Let's take a look at an example:\n\n```tsx\n// /routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n // Consider the route's data fresh for 10 seconds\n staleTime: 10_000,\n})\n```\n\nBy passing `10_000` to the `staleTime` option, we are telling the router to consider the route's data fresh for 10 seconds. This means that if the user navigates to `/posts` from `/about` within 10 seconds of the last loader result, the route's data will not be reloaded. If the user then navigates to `/posts` from `/about` after 10 seconds, the route's data will be reloaded **in the background**.\n\n## Turning off stale-while-revalidate caching\n\nTo disable stale-while-revalidate caching for a route, set the `staleTime` option to `Infinity`:\n\n```tsx\n// /routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n staleTime: Infinity,\n})\n```\n\nYou can even turn this off for all routes by setting the `defaultStaleTime` option on the router:\n\n```tsx\nconst router = createRouter({\n routeTree,\n defaultStaleTime: Infinity,\n})\n```\n\n## Using `shouldReload` and `gcTime` to opt-out of caching\n\nSimilar to Remix's default functionality, you may want to configure a route to only load on entry or when critical loader deps change. You can do this by using the `gcTime` option combined with the `shouldReload` option, which accepts either a `boolean` or a function that receives the same `beforeLoad` and `loaderContext` parameters and returns a boolean indicating if the route should reload.\n\n```tsx\n// /routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loaderDeps: ({ search: { offset, limit } }) => ({ offset, limit }),\n loader: ({ deps }) => fetchPosts(deps),\n // Do not cache this route's data after it's unloaded\n gcTime: 0,\n // Only reload the route when the user navigates to it or when deps change\n shouldReload: false,\n})\n```\n\n### Opting out of caching while still preloading\n\nEven though you may opt-out of short-term caching for your route data, you can still get the benefits of preloading! With the above configuration, preloading will still \"just work\" with the default `preloadGcTime`. This means that if a route is preloaded, then navigated to, the route's data will be considered fresh and will not be reloaded.\n\nTo opt out of preloading, don't turn it on via the `routerOptions.defaultPreload` or `routeOptions.preload` options.\n\n## Passing all loader events to an external cache\n\nWe break down this use case in the [External Data Loading](./external-data-loading.md) page, but if you'd like to use an external cache like TanStack Query, you can do so by passing all loader events to your external cache. As long as you are using the defaults, the only change you'll need to make is to set the `defaultPreloadStaleTime` option on the router to `0`:\n\n```tsx\nconst router = createRouter({\n routeTree,\n defaultPreloadStaleTime: 0,\n})\n```\n\nThis will ensure that every preload, load, and reload event will trigger your `loader` functions, which can then be handled and deduped by your external cache.\n\n## Using Router Context\n\nThe `context` argument passed to the `loader` function is an object containing a merged union of:\n\n- Parent route context\n- This route's context as provided by the `beforeLoad` option\n\nStarting at the very top of the router, you can pass an initial context to the router via the `context` option. This context will be available to all routes in the router and get copied and extended by each route as they are matched. This happens by passing a context to a route via the `beforeLoad` option. This context will be available to all the route's child routes. The resulting context will be available to the route's `loader` function.\n\nIn this example, we'll create a function in our route context to fetch posts, then use it in our `loader` function.\n\n> \uD83E\uDDE0 Context is a powerful tool for dependency injection. You can use it to inject services, hooks, and other objects into your router and routes. You can also additively pass data down the route tree at every route using a route's `beforeLoad` option.\n\n- `/utils/fetchPosts.tsx`\n\n```tsx\nexport const fetchPosts = async () => {\n const res = await fetch(`/api/posts?page=${pageIndex}`)\n if (!res.ok) throw new Error('Failed to fetch posts')\n return res.json()\n}\n```\n\n- `/routes/__root.tsx`\n\n```tsx\nimport { createRootRouteWithContext } from '@tanstack/react-router'\n\n// Create a root route using the createRootRouteWithContext<{...}>() function and pass it whatever types you would like to be available in your router context.\nexport const Route = createRootRouteWithContext<{\n fetchPosts: typeof fetchPosts\n}>()() // NOTE: the double call is on purpose, since createRootRouteWithContext is a factory ;)\n```\n\n- `/routes/posts.tsx`\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\n// Notice how our postsRoute references context to get our fetchPosts function\n// This can be a powerful tool for dependency injection across your router\n// and routes.\nexport const Route = createFileRoute('/posts')({\n loader: ({ context: { fetchPosts } }) => fetchPosts(),\n})\n```\n\n- `/router.tsx`\n\n```tsx\nimport { routeTree } from './routeTree.gen'\n\n// Use your routerContext to create a new router\n// This will require that you fullfil the type requirements of the routerContext\nconst router = createRouter({\n routeTree,\n context: {\n // Supply the fetchPosts function to the router context\n fetchPosts,\n },\n})\n```\n\n## Using Path Params\n\nTo use path params in your `loader` function, access them via the `params` property on the function's parameters. Here's an example:\n\n```tsx\n// routes/posts.$postId.tsx\nexport const Route = createFileRoute('/posts/$postId')({\n loader: ({ params: { postId } }) => fetchPostById(postId),\n})\n```\n\n## Using Route Context\n\nPassing down global context to your router is great, but what if you want to provide context that is specific to a route? This is where the `beforeLoad` option comes in. The `beforeLoad` option is a function that runs right before attempting to load a route and receives the same parameters as `loader`. Beyond its ability to redirect potential matches, block loader requests, etc, it can also return an object that will be merged into the route's context. Let's take a look at an example where we inject some data into our route context via the `beforeLoad` option:\n\n```tsx\n// /routes/posts.tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts')({\n // Pass the fetchPosts function to the route context\n beforeLoad: () => ({\n fetchPosts: () => console.info('foo'),\n }),\n loader: ({ context: { fetchPosts } }) => {\n console.info(fetchPosts()) // 'foo'\n\n // ...\n },\n})\n```\n\n## Using Search Params in Loaders\n\n> \u2753 But wait Tanner... where the heck are my search params?!\n\nYou might be here wondering why `search` isn't directly available in the `loader` function's parameters. We've purposefully designed it this way to help you succeed. Let's take a look at why:\n\n- Search Parameters being used in a loader function are a very good indicator that those search params should also be used to uniquely identify the data being loaded. For example, you may have a route that uses a search param like `pageIndex` that uniquely identifies the data held inside of the route match. Or, imagine a `/users/user` route that uses the search param `userId` to identify a specific user in your application, you might model your url like this: `/users/user?userId=123`. This means that your `user` route would need some extra help to identify a specific user.\n- Directly accessing search params in a loader function can lead to bugs in caching and preloading where the data being loaded is not unique to the current URL pathname and search params. For example, you might ask your `/posts` route to preload page 2's results, but without the distinction of pages in your route configuration, you will end up fetching, storing and displaying page 2's data on your `/posts` or `?page=1` screen instead of it preloading in the background!\n- Placing a threshold between search parameters and the loader function allows the router to understand your dependencies and reactivity.\n\n```tsx\n// /routes/users.user.tsx\nexport const Route = createFileRoute('/users/user')({\n validateSearch: (search) =>\n search as {\n userId: string\n },\n loaderDeps: ({ search: { userId } }) => ({\n userId,\n }),\n loader: async ({ deps: { userId } }) => getUser(userId),\n})\n```\n\n### Accessing Search Params via `routeOptions.loaderDeps`\n\n```tsx\n// /routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n // Use zod to validate and parse the search params\n validateSearch: z.object({\n offset: z.number().int().nonnegative().catch(0),\n }),\n // Pass the offset to your loader deps via the loaderDeps function\n loaderDeps: ({ search: { offset } }) => ({ offset }),\n // Use the offset from context in the loader function\n loader: async ({ deps: { offset } }) =>\n fetchPosts({\n offset,\n }),\n})\n```\n\n## Using the Abort Signal\n\nThe `abortController` property of the `loader` function is an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController). Its signal is cancelled when the route is unloaded or when the `loader` call becomes outdated. This is useful for cancelling network requests when the route is unloaded or when the route's params change. Here is an example using it with a fetch call:\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: ({ abortController }) =>\n fetchPosts({\n // Pass this to an underlying fetch call or anything that supports signals\n signal: abortController.signal,\n }),\n})\n```\n\n## Using the `preload` flag\n\nThe `preload` property of the `loader` function is a boolean which is `true` when the route is being preloaded instead of loaded. Some data loading libraries may handle preloading differently than a standard fetch, so you may want to pass `preload` to your data loading library, or use it to execute the appropriate data loading logic:\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: async ({ preload }) =>\n fetchPosts({\n maxAge: preload ? 10_000 : 0, // Preloads should hang around a bit longer\n }),\n})\n```\n\n## Handling Slow Loaders\n\nIdeally most route loaders can resolve their data within a short moment, removing the need to render a placeholder spinner and simply rely on suspense to render the next route when it's completely ready. When critical data that is required to render a route's component is slow though, you have 2 options:\n\n- Split up your fast and slow data into separate promises and `defer` the slow data until after the fast data is loaded (see the [Deferred Data Loading](./deferred-data-loading.md) guide).\n- Show a pending component after an optimistic suspense threshold until all of the data is ready (See below).\n\n## Showing a pending component\n\n**By default, TanStack Router will show a pending component for loaders that take longer than 1 second to resolve.** This is an optimistic threshold that can be configured via:\n\n- `routeOptions.pendingMs` or\n- `routerOptions.defaultPendingMs`\n\nWhen the pending time threshold is exceeded, the router will render the `pendingComponent` option of the route, if configured.\n\n## Avoiding Pending Component Flash\n\nIf you're using a pending component, the last thing you want is for your pending time threshold to be met, then have your data resolve immediately after, resulting in a jarring flash of your pending component. To avoid this, **TanStack Router by default will show your pending component for at least 500ms**. This is an optimistic threshold that can be configured via:\n\n- `routeOptions.pendingMinMs` or\n- `routerOptions.defaultPendingMinMs`\n\n## Handling Errors\n\nTanStack Router provides a few ways to handle errors that occur during the route loading lifecycle. Let's take a look at them.\n\n### Handling Errors with `routeOptions.onError`\n\nThe `routeOptions.onError` option is a function that is called when an error occurs during the route loading.\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n onError: ({ error }) => {\n // Log the error\n console.error(error)\n },\n})\n```\n\n### Handling Errors with `routeOptions.onCatch`\n\nThe `routeOptions.onCatch` option is a function that is called whenever an error was caught by the router's CatchBoundary.\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n onCatch: ({ error, errorInfo }) => {\n // Log the error\n console.error(error)\n },\n})\n```\n\n### Handling Errors with `routeOptions.errorComponent`\n\nThe `routeOptions.errorComponent` option is a component that is rendered when an error occurs during the route loading or rendering lifecycle. It is rendered with the following props:\n\n- `error` - The error that occurred\n- `reset` - A function to reset the internal `CatchBoundary`\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n errorComponent: ({ error }) => {\n // Render an error message\n return <div>{error.message}</div>\n },\n})\n```\n\nThe `reset` function can be used to allow the user to retry rendering the error boundaries normal children:\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n errorComponent: ({ error, reset }) => {\n return (\n <div>\n {error.message}\n <button\n onClick={() => {\n // Reset the router error boundary\n reset()\n }}\n >\n retry\n </button>\n </div>\n )\n },\n})\n```\n\nIf the error was the result of a route load, you should instead call `router.invalidate()`, which will coordinate both a router reload and an error boundary reset:\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n errorComponent: ({ error, reset }) => {\n const router = useRouter()\n\n return (\n <div>\n {error.message}\n <button\n onClick={() => {\n // Invalidate the route to reload the loader, which will also reset the error boundary\n router.invalidate()\n }}\n >\n retry\n </button>\n </div>\n )\n },\n})\n```\n\n### Using the default `ErrorComponent`\n\nTanStack Router provides a default `ErrorComponent` that is rendered when an error occurs during the route loading or rendering lifecycle. If you choose to override your routes' error components, it's still wise to always fall back to rendering any uncaught errors with the default `ErrorComponent`:\n\n```tsx\n// routes/posts.tsx\nimport { createFileRoute, ErrorComponent } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n errorComponent: ({ error }) => {\n if (error instanceof MyCustomError) {\n // Render a custom error message\n return <div>{error.message}</div>\n }\n\n // Fallback to the default ErrorComponent\n return <ErrorComponent error={error} />\n },\n})\n```\n\n# Data Mutations\n\nSince TanStack router does not store or cache data, it's role in data mutation is slim to none outside of reacting to potential URL side-effects from external mutation events. That said, we've compiled a list of mutation-related features you might find useful and libraries that implement them.\n\nLook for and use mutation utilities that support:\n\n- Handling and caching submission state\n- Providing both local and global optimistic UI support\n- Built-in hooks to wire up invalidation (or automatically support it)\n- Handling multiple in-flight mutations at once\n- Organizing mutation state as a globally accessible resource\n- Submission state history and garbage collection\n\nSome suggested libraries:\n\n- [TanStack Query](https://tanstack.com/query/latest/docs/react/guides/mutations)\n- [SWR](https://swr.vercel.app/)\n- [RTK Query](https://redux-toolkit.js.org/rtk-query/overview)\n- [urql](https://formidable.com/open-source/urql/)\n- [Relay](https://relay.dev/)\n- [Apollo](https://www.apollographql.com/docs/react/)\n\nOr, even...\n\n- [Zustand](https://zustand-demo.pmnd.rs/)\n- [Jotai](https://jotai.org/)\n- [Recoil](https://recoiljs.org/)\n- [Redux](https://redux.js.org/)\n\nSimilar to data fetching, mutation state isn't a one-size-fits-all solution, so you'll need to pick a solution that fits your needs and your team's needs. We recommend trying out a few different solutions and seeing what works best for you.\n\n> \u26A0\uFE0F Still here? Submission state is an interesting topic when it comes to persistence. Do you keep every mutation around forever? How do you know when to get rid of it? What if the user navigates away from the screen and then back? Let's dig in!\n\n## Invalidating TanStack Router after a mutation\n\nTanStack Router comes with short-term caching built-in. So even though we're not storing any data after a route match is unmounted, there is a high probability that if any mutations are made related to the data stored in the Router, the current route matches' data could become stale.\n\nWhen mutations related to loader data are made, we can use `router.invalidate` to force the router to reload all of the current route matches:\n\n```tsx\nconst router = useRouter()\n\nconst addTodo = async (todo: Todo) => {\n try {\n await api.addTodo()\n router.invalidate()\n } catch {\n //\n }\n}\n```\n\nInvalidating all of the current route matches happens in the background, so existing data will continue to be served until the new data is ready, just as if you were navigating to a new route.\n\nIf you want to await the invalidation until all loaders have finished, pass `{sync: true}` into `router.invalidate`:\n\n```tsx\nconst router = useRouter()\n\nconst addTodo = async (todo: Todo) => {\n try {\n await api.addTodo()\n await router.invalidate({ sync: true })\n } catch {\n //\n }\n}\n```\n\n## Long-term mutation State\n\nRegardless of the mutation library used, mutations often create state related to their submission. While most mutations are set-and-forget, some mutation states are more long-lived, either to support optimistic UI or to provide feedback to the user about the status of their submissions. Most state managers will correctly keep this submission state around and expose it to make it possible to show UI elements like loading spinners, success messages, error messages, etc.\n\nLet's consider the following interactions:\n\n- User navigates to the `/posts/123/edit` screen to edit a post\n- User edits the `123` post and upon success, sees a success message below the editor that the post was updated\n- User navigates to the `/posts` screen\n- User navigates back to the `/posts/123/edit` screen again\n\nWithout notifying your mutation management library about the route change, it's possible that your submission state could still be around and your user would still see the **\"Post updated successfully\"** message when they return to the previous screen. This is not ideal. Obviously, our intent wasn't to keep this mutation state around forever, right?!\n\n## Using mutation keys\n\nHopefully and hypothetically, the easiest way is for your mutation library to support a keying mechanism that will allow your mutations's state to be reset when the key changes:\n\n```tsx\nconst routeApi = getRouteApi('/room/$roomId/chat')\n\nfunction ChatRoom() {\n const { roomId } = routeApi.useParams()\n\n const sendMessageMutation = useCoolMutation({\n fn: sendMessage,\n // Clear the mutation state when the roomId changes\n // including any submission state\n key: ['sendMessage', roomId],\n })\n\n // Fire off a bunch of messages\n const test = () => {\n sendMessageMutation.mutate({ roomId, message: 'Hello!' })\n sendMessageMutation.mutate({ roomId, message: 'How are you?' })\n sendMessageMutation.mutate({ roomId, message: 'Goodbye!' })\n }\n\n return (\n <>\n {sendMessageMutation.submissions.map((submission) => {\n return (\n <div>\n <div>{submission.status}</div>\n <div>{submission.message}</div>\n </div>\n )\n })}\n </>\n )\n}\n```\n\n## Using the `router.subscribe` method\n\nFor libraries that don't have a keying mechanism, we'll likely need to manually reset the mutation state when the user navigates away from the screen. To solve this, we can use TanStack Router's `invalidate` and `subscribe` method to clear mutation states when the user is no longer in need of them.\n\nThe `router.subscribe` method is a function that subscribes a callback to various router events. The event in particular that we'll use here is the `onResolved` event. It's important to understand that this event is fired when the location path is _changed (not just reloaded) and has finally resolved_.\n\nThis is a great place to reset your old mutation states. Here's an example:\n\n```tsx\nconst router = createRouter()\nconst coolMutationCache = createCoolMutationCache()\n\nconst unsubscribeFn = router.subscribe('onResolved', () => {\n // Reset mutation states when the route changes\n coolMutationCache.clear()\n})\n```\n\n# Deferred Data Loading\n\nTanStack Router is designed to run loaders in parallel and wait for all of them to resolve before rendering the next route. This is great most of the time, but occasionally, you may want to show the user something sooner while the rest of the data loads in the background.\n\nDeferred data loading is a pattern that allows the router to render the next location's critical data/markup while slower, non-critical route data is resolved in the background. This process works on both the client and server (via streaming) and is a great way to improve the perceived performance of your application.\n\nIf you are using a library like [TanStack Query](https://tanstack.com/query/latest) or any other data fetching library, then deferred data loading works a bit differently. Skip ahead to the [Deferred Data Loading with External Libraries](#deferred-data-loading-with-external-libraries) section for more information.\n\n## Deferred Data Loading with `Await`\n\nTo defer slow or non-critical data, return an **unawaited/unresolved** promise anywhere in your loader response:\n\n```tsx\n// src/routes/posts.$postId.tsx\nimport { createFileRoute, defer } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async () => {\n // Fetch some slower data, but do not await it\n const slowDataPromise = fetchSlowData()\n\n // Fetch and await some data that resolves quickly\n const fastData = await fetchFastData()\n\n return {\n fastData,\n deferredSlowData: slowDataPromise,\n }\n },\n})\n```\n\nAs soon as any awaited promises are resolved, the next route will begin rendering while the deferred promises continue to resolve.\n\nIn the component, deferred promises can be resolved and utilized using the `Await` component:\n\n```tsx\n// src/routes/posts.$postId.tsx\nimport { createFileRoute, Await } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts/$postId')({\n // ...\n component: PostIdComponent,\n})\n\nfunction PostIdComponent() {\n const { deferredSlowData, fastData } = Route.useLoaderData()\n\n // do something with fastData\n\n return (\n <Await promise={deferredSlowData} fallback={<div>Loading...</div>}>\n {(data) => {\n return <div>{data}</div>\n }}\n </Await>\n )\n}\n```\n\n> [!TIP]\n> If your component is code-split, you can use the [getRouteApi function](./code-splitting.md#manually-accessing-route-apis-in-other-files-with-the-getrouteapi-helper) to avoid having to import the `Route` configuration to get access to the typed `useLoaderData()` hook.\n\nThe `Await` component resolves the promise by triggering the nearest suspense boundary until it is resolved, after which it renders the component's `children` as a function with the resolved data.\n\nIf the promise is rejected, the `Await` component will throw the serialized error, which can be caught by the nearest error boundary.\n\n[//]: # 'DeferredWithAwaitFinalTip'\n\n> [!TIP]\n> In React 19, you can use the `use()` hook instead of `Await`\n\n[//]: # 'DeferredWithAwaitFinalTip'\n\n## Deferred Data Loading with External libraries\n\nWhen your strategy for fetching information for the route relies on [External Data Loading](./external-data-loading.md) with an external library like [TanStack Query](https://tanstack.com/query), deferred data loading works a bit differently, as the library handles the data fetching and caching for you outside of TanStack Router.\n\nSo, instead of using `defer` and `Await`, you'll instead want to use the Route's `loader` to kick off the data fetching and then use the library's hooks to access the data in your components.\n\n```tsx\n// src/routes/posts.$postId.tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { slowDataOptions, fastDataOptions } from '~/api/query-options'\n\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ context: { queryClient } }) => {\n // Kick off the fetching of some slower data, but do not await it\n queryClient.prefetchQuery(slowDataOptions())\n\n // Fetch and await some data that resolves quickly\n await queryClient.ensureQueryData(fastDataOptions())\n },\n})\n```\n\nThen in your component, you can use the library's hooks to access the data:\n\n```tsx\n// src/routes/posts.$postId.tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { useSuspenseQuery } from '@tanstack/react-query'\nimport { slowDataOptions, fastDataOptions } from '~/api/query-options'\n\nexport const Route = createFileRoute('/posts/$postId')({\n // ...\n component: PostIdComponent,\n})\n\nfunction PostIdComponent() {\n const fastData = useSuspenseQuery(fastDataOptions())\n\n // do something with fastData\n\n return (\n <Suspense fallback={<div>Loading...</div>}>\n <SlowDataComponent />\n </Suspense>\n )\n}\n\nfunction SlowDataComponent() {\n const data = useSuspenseQuery(slowDataOptions())\n\n return <div>{data}</div>\n}\n```\n\n## Caching and Invalidation\n\nStreamed promises follow the same lifecycle as the loader data they are associated with. They can even be preloaded!\n\n[//]: # 'SSRContent'\n\n## SSR & Streaming Deferred Data\n\n**Streaming requires a server that supports it and for TanStack Router to be configured to use it properly.**\n\nPlease read the entire [Streaming SSR Guide](./ssr.md#streaming-ssr) for step by step instructions on how to set up your server for streaming.\n\n## SSR Streaming Lifecycle\n\nThe following is a high-level overview of how deferred data streaming works with TanStack Router:\n\n- Server\n - Promises are marked and tracked as they are returned from route loaders\n - All loaders resolve and any deferred promises are serialized and embedded into the html\n - The route begins to render\n - Deferred promises rendered with the `<Await>` component trigger suspense boundaries, allowing the server to stream html up to that point\n- Client\n - The client receives the initial html from the server\n - `<Await>` components suspend with placeholder promises while they wait for their data to resolve on the server\n- Server\n - As deferred promises resolve, their results (or errors) are serialized and streamed to the client via an inline script tag\n - The resolved `<Await>` components and their suspense boundaries are resolved and their resulting HTML is streamed to the client along with their dehydrated data\n- Client\n - The suspended placeholder promises within `<Await>` are resolved with the streamed data/error responses and either render the result or throw the error to the nearest error boundary\n\n[//]: # 'SSRContent'\n\n# Document Head Management\n\nDocument head management is the process of managing the head, title, meta, link, and script tags of a document and TanStack Router provides a robust way to manage the document head for full-stack applications that use Start and for single-page applications that use `@tanstack/react-router`. It provides:\n\n- Automatic deduping of `title` and `meta` tags\n- Automatic loading/unloading of tags based on route visibility\n- A composable way to merge `title` and `meta` tags from nested routes\n\nFor full-stack applications that use Start, and even for single-page applications that use `@tanstack/react-router`, managing the document head is a crucial part of any application for the following reasons:\n\n- SEO\n- Social media sharing\n- Analytics\n- CSS and JS loading/unloading\n\nTo manage the document head, it's required that you render both the `<HeadContent />` and `<Scripts />` components and use the `routeOptions.head` property to manage the head of a route, which returns an object with `title`, `meta`, `links`, `styles`, and `scripts` properties.\n\n## Managing the Document Head\n\n```tsx\nexport const Route = createRootRoute({\n head: () => ({\n meta: [\n {\n name: 'description',\n content: 'My App is a web application',\n },\n {\n title: 'My App',\n },\n ],\n links: [\n {\n rel: 'icon',\n href: '/favicon.ico',\n },\n ],\n styles: [\n {\n media: 'all and (max-width: 500px)',\n children: `p {\n color: blue;\n background-color: yellow;\n }`,\n },\n ],\n scripts: [\n {\n src: 'https://www.google-analytics.com/analytics.js',\n },\n ],\n }),\n})\n```\n\n### Deduping\n\nOut of the box, TanStack Router will dedupe `title` and `meta` tags, preferring the **last** occurrence of each tag found in nested routes.\n\n- `title` tags defined in nested routes will override a `title` tag defined in a parent route (but you can compose them together, which is covered in a future section of this guide)\n- `meta` tags with the same `name` or `property` will be overridden by the last occurrence of that tag found in nested routes\n\n### `<HeadContent />`\n\nThe `<HeadContent />` component is **required** to render the head, title, meta, link, and head-related script tags of a document.\n\nIt should be **rendered either in the `<head>` tag of your root layout or as high up in the component tree as possible** if your application doesn't or can't manage the `<head>` tag.\n\n### Start/Full-Stack Applications\n\n```tsx\nimport { HeadContent } from '@tanstack/react-router'\n\nexport const Route = createRootRoute({\n component: () => (\n <html>\n <head>\n <HeadContent />\n </head>\n <body>\n <Outlet />\n </body>\n </html>\n ),\n})\n```\n\n### Single-Page Applications\n\nFirst, remove the `<title>` tag from the the index.html if you have set any.\n\n```tsx\nimport { HeadContent } from '@tanstack/react-router'\n\nconst rootRoute = createRootRoute({\n component: () => (\n <>\n <HeadContent />\n <Outlet />\n </>\n ),\n})\n```\n\n## Managing Body Scripts\n\nIn addition to scripts that can be rendered in the `<head>` tag, you can also render scripts in the `<body>` tag using the `routeOptions.scripts` property. This is useful for loading scripts (even inline scripts) that require the DOM to be loaded, but before the main entry point of your application (which includes hydration if you're using Start or a full-stack implementation of TanStack Router).\n\nTo do this, you must:\n\n- Use the `scripts` property of the `routeOptions` object\n- [Render the `<Scripts />` component](#scripts)\n\n```tsx\nexport const Route = createRootRoute({\n scripts: () => [\n {\n children: 'console.log(\"Hello, world!\")',\n },\n ],\n})\n```\n\n### `<Scripts />`\n\nThe `<Scripts />` component is **required** to render the body scripts of a document. It should be rendered either in the `<body>` tag of your root layout or as high up in the component tree as possible if your application doesn't or can't manage the `<body>` tag.\n\n### Example\n\n```tsx\nimport { createFileRoute, Scripts } from '@tanstack/react-router'\nexport const Router = createFileRoute('/')({\n component: () => (\n <html>\n <head />\n <body>\n <Outlet />\n <Scripts />\n </body>\n </html>\n ),\n})\n```\n\n```tsx\nimport { Scripts, createRootRoute } from '@tanstack/react-router'\n\nexport const Route = createRootRoute({\n component: () => (\n <>\n <Outlet />\n <Scripts />\n </>\n ),\n})\n```\n\n# External Data Loading\n\n> [!IMPORTANT]\n> This guide is geared towards external state management libraries and their integration with TanStack Router for data fetching, ssr, hydration/dehydration and streaming. If you haven't read the standard [Data Loading](./data-loading.md) guide, please do so first.\n\n## To **Store** or to **Coordinate**?\n\nWhile Router is very capable of storing and managing most data needs out of the box, sometimes you just might want something more robust!\n\nRouter is designed to be a perfect **coordinator** for external data fetching and caching libraries. This means that you can use any data fetching/caching library you want, and the router will coordinate the loading of your data in a way that aligns with your users' navigation and expectations of freshness.\n\n## What data fetching libraries are supported?\n\nAny data fetching library that supports asynchronous promises can be used with TanStack Router. This includes:\n\n- [TanStack Query](https://tanstack.com/query/latest/docs/react/overview)\n- [SWR](https://swr.vercel.app/)\n- [RTK Query](https://redux-toolkit.js.org/rtk-query/overview)\n- [urql](https://formidable.com/open-source/urql/)\n- [Relay](https://relay.dev/)\n- [Apollo](https://www.apollographql.com/docs/react/)\n\nOr, even...\n\n- [Zustand](https://zustand-demo.pmnd.rs/)\n- [Jotai](https://jotai.org/)\n- [Recoil](https://recoiljs.org/)\n- [Redux](https://redux.js.org/)\n\nLiterally any library that **can return a promise and read/write data** can be integrated.\n\n## Using Loaders to ensure data is loaded\n\nThe easiest way to integrate external caching/data library into Router is to use `route.loader`s to ensure that the data required inside of a route has been loaded and is ready to be displayed.\n\n> \u26A0\uFE0F BUT WHY? It's very important to preload your critical render data in the loader for a few reasons:\n>\n> - No \"flash of loading\" states\n> - No waterfall data fetching, caused by component based fetching\n> - Better for SEO. If your data is available at render time, it will be indexed by search engines.\n\nHere is a naive illustration (don't do this) of using a Route's `loader` option to seed the cache for some data:\n\n```tsx\n// src/routes/posts.tsx\nlet postsCache = []\n\nexport const Route = createFileRoute('/posts')({\n loader: async () => {\n postsCache = await fetchPosts()\n },\n component: () => {\n return (\n <div>\n {postsCache.map((post) => (\n <Post key={post.id} post={post} />\n ))}\n </div>\n )\n },\n})\n```\n\nThis example is **obviously flawed**, but illustrates the point that you can use a route's `loader` option to seed your cache with data. Let's take a look at a more realistic example using TanStack Query.\n\n- Replace `fetchPosts` with your preferred data fetching library's prefetching API\n- Replace `postsCache` with your preferred data fetching library's read-or-fetch API or hook\n\n## A more realistic example using TanStack Query\n\nLet's take a look at a more realistic example using TanStack Query.\n\n```tsx\n// src/routes/posts.tsx\nconst postsQueryOptions = queryOptions({\n queryKey: ['posts'],\n queryFn: () => fetchPosts(),\n})\n\nexport const Route = createFileRoute('/posts')({\n // Use the `loader` option to ensure that the data is loaded\n loader: () => queryClient.ensureQueryData(postsQueryOptions),\n component: () => {\n // Read the data from the cache and subscribe to updates\n const {\n data: { posts },\n } = useSuspenseQuery(postsQueryOptions)\n\n return (\n <div>\n {posts.map((post) => (\n <Post key={post.id} post={post} />\n ))}\n </div>\n )\n },\n})\n```\n\n### Error handling with TanStack Query\n\nWhen an error occurs while using `suspense` with `TanStack Query`, you need to let queries know that you want to try again when re-rendering. This can be done by using the `reset` function provided by the `useQueryErrorResetBoundary` hook. You can invoke this function in an effect as soon as the error component mounts. This will make sure that the query is reset and will try to fetch data again when the route component is rendered again. This will also cover cases where users navigate away from the route instead of clicking the `retry` button.\n\n```tsx\nexport const Route = createFileRoute('/')({\n loader: () => queryClient.ensureQueryData(postsQueryOptions),\n errorComponent: ({ error, reset }) => {\n const router = useRouter()\n const queryErrorResetBoundary = useQueryErrorResetBoundary()\n\n useEffect(() => {\n // Reset the query error boundary\n queryErrorResetBoundary.reset()\n }, [queryErrorResetBoundary])\n\n return (\n <div>\n {error.message}\n <button\n onClick={() => {\n // Invalidate the route to reload the loader, and reset any router error boundaries\n router.invalidate()\n }}\n >\n retry\n </button>\n </div>\n )\n },\n})\n```\n\n## SSR Dehydration/Hydration\n\nTools that are able can integrate with TanStack Router's convenient Dehydration/Hydration APIs to shuttle dehydrated data between the server and client and rehydrate it where needed. Let's go over how to do this with both 3rd party critical data and 3rd party deferred data.\n\n## Critical Dehydration/Hydration\n\n**For critical data needed for the first render/paint**, TanStack Router supports **`dehydrate` and `hydrate`** options when configuring the `Router`. These callbacks are functions that are automatically called on the server and client when the router dehydrates and hydrates normally and allow you to augment the dehydrated data with your own data.\n\nThe `dehydrate` function can return any serializable JSON data which will get merged and injected into the dehydrated payload that is sent to the client.\n\nFor example, let's dehydrate and hydrate a TanStack Query `QueryClient` so that our data we fetched on the server will be available for hydration on the client.\n\n```tsx\n// src/router.tsx\n\nexport function createRouter() {\n // Make sure you create your loader client or similar data\n // stores inside of your `createRouter` function. This ensures\n // that your data stores are unique to each request and\n // always present on both server and client.\n const queryClient = new QueryClient()\n\n return createRouter({\n routeTree,\n // Optionally provide your loaderClient to the router context for\n // convenience (you can provide anything you want to the router\n // context!)\n context: {\n queryClient,\n },\n // On the server, dehydrate the loader client so the router\n // can serialize it and send it to the client for us\n dehydrate: () => {\n return {\n queryClientState: dehydrate(queryClient),\n }\n },\n // On the client, hydrate the loader client with the data\n // we dehydrated on the server\n hydrate: (dehydrated) => {\n hydrate(queryClient, dehydrated.queryClientState)\n },\n // Optionally, we can use `Wrap` to wrap our router in the loader client provider\n Wrap: ({ children }) => {\n return (\n <QueryClientProvider client={queryClient}>\n {children}\n </QueryClientProvider>\n )\n },\n })\n}\n```\n\n# History Types\n\nWhile it's not required to know the `@tanstack/history` API itself to use TanStack Router, it's a good idea to understand how it works. Under the hood, TanStack Router requires and uses a `history` abstraction to manage the routing history.\n\nIf you don't create a history instance, a browser-oriented instance of this API is created for you when the router is initialized. If you need a special history API type, You can use the `@tanstack/history` package to create your own:\n\n- `createBrowserHistory`: The default history type.\n- `createHashHistory`: A history type that uses a hash to track history.\n- `createMemoryHistory`: A history type that keeps the history in memory.\n\nOnce you have a history instance, you can pass it to the `Router` constructor:\n\n```ts\nimport { createMemoryHistory, createRouter } from '@tanstack/react-router'\n\nconst memoryHistory = createMemoryHistory({\n initialEntries: ['/'], // Pass your initial url\n})\n\nconst router = createRouter({ routeTree, history: memoryHistory })\n```\n\n## Browser Routing\n\nThe `createBrowserHistory` is the default history type. It uses the browser's history API to manage the browser history.\n\n## Hash Routing\n\nHash routing can be helpful if your server doesn't support rewrites to index.html for HTTP requests (among other environments that don't have a server).\n\n```ts\nimport { createHashHistory, createRouter } from '@tanstack/react-router'\n\nconst hashHistory = createHashHistory()\n\nconst router = createRouter({ routeTree, history: hashHistory })\n```\n\n## Memory Routing\n\nMemory routing is useful in environments that are not a browser or when you do not want components to interact with the URL.\n\n```ts\nimport { createMemoryHistory, createRouter } from '@tanstack/react-router'\n\nconst memoryHistory = createMemoryHistory({\n initialEntries: ['/'], // Pass your initial url\n})\n\nconst router = createRouter({ routeTree, history: memoryHistory })\n```\n\nRefer to the [SSR Guide](./ssr.md#server-history) for usage on the server for server-side rendering.\n\n# Link Options\n\nYou may want to reuse options that are intended to be passed to `Link`, `redirect` or `navigate`. In which case you may decide an object literal is a good way to represent options passed to `Link`.\n\n```tsx\nconst dashboardLinkOptions = {\n to: '/dashboard',\n search: { search: '' },\n}\n\nfunction DashboardComponent() {\n return <Link {...dashboardLinkOptions} />\n}\n```\n\nThere are a few problems here. `dashboardLinkOptions.to` is inferred as `string` which by default will resolve to every route when passed to `Link`, `navigate` or `redirect` (this particular issue could be fixed by `as const`). The other issue here is we do not know `dashboardLinkOptions` even passes the type checker until it is spread into `Link`. We could very easily create incorrect navigation options and only when the options are spread into `Link` do we know there is a type error.\n\n### Using `linkOptions` function to create re-usable options\n\n`linkOptions` is a function which type checks an object literal and returns the inferred input as is. This provides type safety on options exactly like `Link` before it is used allowing for easier maintenance and re-usability. Our above example using `linkOptions` looks like this:\n\n```tsx\nconst dashboardLinkOptions = linkOptions({\n to: '/dashboard',\n search: { search: '' },\n})\n\nfunction DashboardComponent() {\n return <Link {...dashboardLinkOptions} />\n}\n```\n\nThis allows eager type checking of `dashboardLinkOptions` which can then be re-used anywhere\n\n```tsx\nconst dashboardLinkOptions = linkOptions({\n to: '/dashboard',\n search: { search: '' },\n})\n\nexport const Route = createFileRoute('/dashboard')({\n component: DashboardComponent,\n validateSearch: (input) => ({ search: input.search }),\n beforeLoad: () => {\n // can used in redirect\n throw redirect(dashboardLinkOptions)\n },\n})\n\nfunction DashboardComponent() {\n const navigate = useNavigate()\n\n return (\n <div>\n {/** can be used in navigate */}\n <button onClick={() => navigate(dashboardLinkOptions)} />\n\n {/** can be used in Link */}\n <Link {...dashboardLinkOptions} />\n </div>\n )\n}\n```\n\n### An array of `linkOptions`\n\nWhen creating navigation you might loop over an array to construct a navigation bar. In which case `linkOptions` can be used to type check an array of object literals which are intended for `Link` props\n\n```tsx\nconst options = linkOptions([\n {\n to: '/dashboard',\n label: 'Summary',\n activeOptions: { exact: true },\n },\n {\n to: '/dashboard/invoices',\n label: 'Invoices',\n },\n {\n to: '/dashboard/users',\n label: 'Users',\n },\n])\n\nfunction DashboardComponent() {\n return (\n <>\n <div className=\"flex items-center border-b\">\n <h2 className=\"text-xl p-2\">Dashboard</h2>\n </div>\n\n <div className=\"flex flex-wrap divide-x\">\n {options.map((option) => {\n return (\n <Link\n {...option}\n key={option.to}\n activeProps={{ className: `font-bold` }}\n className=\"p-2\"\n >\n {option.label}\n </Link>\n )\n })}\n </div>\n <hr />\n\n <Outlet />\n </>\n )\n}\n```\n\nThe input of `linkOptions` is inferred and returned, as shown with the use of `label` as this does not exist on `Link` props\n\n# Navigation Blocking\n\nNavigation blocking is a way to prevent navigation from happening. This is typical if a user attempts to navigate while they:\n\n- Have unsaved changes\n- Are in the middle of a form\n- Are in the middle of a payment\n\nIn these situations, a prompt or custom UI should be shown to the user to confirm they want to navigate away.\n\n- If the user confirms, navigation will continue as normal\n- If the user cancels, all pending navigations will be blocked\n\n## How does navigation blocking work?\n\nNavigation blocking adds one or more layers of \"blockers\" to the entire underlying history API. If any blockers are present, navigation will be paused via one of the following ways:\n\n- Custom UI\n - If the navigation is triggered by something we control at the router level, we can allow you to perform any task or show any UI you'd like to the user to confirm the action. Each blocker's `blocker` function will be asynchronously and sequentially executed. If any blocker function resolves or returns `true`, the navigation will be allowed and all other blockers will continue to do the same until all blockers have been allowed to proceed. If any single blocker resolves or returns `false`, the navigation will be canceled and the rest of the `blocker` functions will be ignored.\n- The `onbeforeunload` event\n - For page events that we cannot control directly, we rely on the browser's `onbeforeunload` event. If the user attempts to close the tab or window, refresh, or \"unload\" the page assets in any way, the browser's generic \"Are you sure you want to leave?\" dialog will be shown. If the user confirms, all blockers will be bypassed and the page will unload. If the user cancels, the unload will be cancelled, and the page will remain as is.\n\n## How do I use navigation blocking?\n\nThere are 2 ways to use navigation blocking:\n\n- Hook/logical-based blocking\n- Component-based blocking\n\n## Hook/logical-based blocking\n\nLet's imagine we want to prevent navigation if a form is dirty. We can do this by using the `useBlocker` hook:\n\n[//]: # 'HookBasedBlockingExample'\n\n```tsx\nimport { useBlocker } from '@tanstack/react-router'\n\nfunction MyComponent() {\n const [formIsDirty, setFormIsDirty] = useState(false)\n\n useBlocker({\n shouldBlockFn: () => {\n if (!formIsDirty) return false\n\n const shouldLeave = confirm('Are you sure you want to leave?')\n return !shouldLeave\n },\n })\n\n // ...\n}\n```\n\n[//]: # 'HookBasedBlockingExample'\n\n`shouldBlockFn` gives you type safe access to the `current` and `next` location:\n\n```tsx\nimport { useBlocker } from '@tanstack/react-router'\n\nfunction MyComponent() {\n // always block going from /foo to /bar/123?hello=world\n const { proceed, reset, status } = useBlocker({\n shouldBlockFn: ({ current, next }) => {\n return (\n current.routeId === '/foo' &&\n next.fullPath === '/bar/$id' &&\n next.params.id === 123 &&\n next.search.hello === 'world'\n )\n },\n withResolver: true,\n })\n\n // ...\n}\n```\n\nNote that even if `shouldBlockFn` returns `false`, the browser's `beforeunload` event may still be triggered on page reloads or tab closing. To gain control over this, you can use the `enableBeforeUnload` option to conditionally register the `beforeunload` handler:\n\n[//]: # 'HookBasedBlockingExample'\n\n```tsx\nimport { useBlocker } from '@tanstack/react-router'\n\nfunction MyComponent() {\n const [formIsDirty, setFormIsDirty] = useState(false)\n\n useBlocker({\n {/* ... */}\n enableBeforeUnload: formIsDirty, // or () => formIsDirty\n })\n\n // ...\n}\n```\n\nYou can find more information about the `useBlocker` hook in the [API reference](../api/router/useBlockerHook.md).\n\n## Component-based blocking\n\nIn addition to logical/hook based blocking, you can use the `Block` component to achieve similar results:\n\n[//]: # 'ComponentBasedBlockingExample'\n\n```tsx\nimport { Block } from '@tanstack/react-router'\n\nfunction MyComponent() {\n const [formIsDirty, setFormIsDirty] = useState(false)\n\n return (\n <Block\n shouldBlockFn={() => {\n if (!formIsDirty) return false\n\n const shouldLeave = confirm('Are you sure you want to leave?')\n return !shouldLeave\n }}\n enableBeforeUnload={formIsDirty}\n />\n )\n\n // OR\n\n return (\n <Block\n shouldBlockFn={() => formIsDirty}\n enableBeforeUnload={formIsDirty}\n withResolver\n >\n {({ status, proceed, reset }) => <>{/* ... */}</>}\n </Block>\n )\n}\n```\n\n[//]: # 'ComponentBasedBlockingExample'\n\n## How can I show a custom UI?\n\nIn most cases, using `window.confirm` in the `shouldBlockFn` function with `withResolver: false` in the hook is enough since it will clearly show the user that the navigation is being blocked and resolve the blocking based on their response.\n\nHowever, in some situations, you might want to show a custom UI that is intentionally less disruptive and more integrated with your app's design.\n\n**Note:** The return value of `shouldBlockFn` does not resolve the blocking if `withResolver` is `true`.\n\n### Hook/logical-based custom UI with resolver\n\n[//]: # 'HookBasedCustomUIBlockingWithResolverExample'\n\n```tsx\nimport { useBlocker } from '@tanstack/react-router'\n\nfunction MyComponent() {\n const [formIsDirty, setFormIsDirty] = useState(false)\n\n const { proceed, reset, status } = useBlocker({\n shouldBlockFn: () => formIsDirty,\n withResolver: true,\n })\n\n // ...\n\n return (\n <>\n {/* ... */}\n {status === 'blocked' && (\n <div>\n <p>Are you sure you want to leave?</p>\n <button onClick={proceed}>Yes</button>\n <button onClick={reset}>No</button>\n </div>\n )}\n </>\n}\n```\n\n[//]: # 'HookBasedCustomUIBlockingWithResolverExample'\n\n### Hook/logical-based custom UI without resolver\n\n[//]: # 'HookBasedCustomUIBlockingWithoutResolverExample'\n\n```tsx\nimport { useBlocker } from '@tanstack/react-router'\n\nfunction MyComponent() {\n const [formIsDirty, setFormIsDirty] = useState(false)\n\n useBlocker({\n shouldBlockFn: () => {\n if (!formIsDirty) {\n return false\n }\n\n const shouldBlock = new Promise<boolean>((resolve) => {\n // Using a modal manager of your choice\n modals.open({\n title: 'Are you sure you want to leave?',\n children: (\n <SaveBlocker\n confirm={() => {\n modals.closeAll()\n resolve(false)\n }}\n reject={() => {\n modals.closeAll()\n resolve(true)\n }}\n />\n ),\n onClose: () => resolve(true),\n })\n })\n return shouldBlock\n },\n })\n\n // ...\n}\n```\n\n[//]: # 'HookBasedCustomUIBlockingWithoutResolverExample'\n\n### Component-based custom UI\n\nSimilarly to the hook, the `Block` component returns the same state and functions as render props:\n\n[//]: # 'ComponentBasedCustomUIBlockingExample'\n\n```tsx\nimport { Block } from '@tanstack/react-router'\n\nfunction MyComponent() {\n const [formIsDirty, setFormIsDirty] = useState(false)\n\n return (\n <Block shouldBlockFn={() => formIsDirty} withResolver>\n {({ status, proceed, reset }) => (\n <>\n {/* ... */}\n {status === 'blocked' && (\n <div>\n <p>Are you sure you want to leave?</p>\n <button onClick={proceed}>Yes</button>\n <button onClick={reset}>No</button>\n </div>\n )}\n </>\n )}\n </Block>\n )\n}\n```\n\n[//]: # 'ComponentBasedCustomUIBlockingExample'\n\n# Navigation\n\n## Everything is Relative\n\nBelieve it or not, every navigation within an app is **relative**, even if you aren't using explicit relative path syntax (`../../somewhere`). Any time a link is clicked or an imperative navigation call is made, you will always have an **origin** path and a **destination** path which means you are navigating **from** one route **to** another route.\n\nTanStack Router keeps this constant concept of relative navigation in mind for every navigation, so you'll constantly see two properties in the API:\n\n- `from` - The origin route path\n- `to` - The destination route path\n\n> \u26A0\uFE0F If a `from` route path isn't provided the router will assume you are navigating from the root `/` route and only auto-complete absolute paths. After all, you need to know where you are from in order to know where you're going \uD83D\uDE09.\n\n## Shared Navigation API\n\nEvery navigation and route matching API in TanStack Router uses the same core interface with minor differences depending on the API. This means that you can learn navigation and route matching once and use the same syntax and concepts across the library.\n\n### `ToOptions` Interface\n\nThis is the core `ToOptions` interface that is used in every navigation and route matching API:\n\n```ts\ntype ToOptions<\n TRouteTree extends AnyRoute = AnyRoute,\n TFrom extends RoutePaths<TRouteTree> | string = string,\n TTo extends string = '',\n> = {\n // `from` is an optional route ID or path. If it is not supplied, only absolute paths will be auto-completed and type-safe. It's common to supply the route.fullPath of the origin route you are rendering from for convenience. If you don't know the origin route, leave this empty and work with absolute paths or unsafe relative paths.\n from?: string\n // `to` can be an absolute route path or a relative path from the `from` option to a valid route path. \u26A0\uFE0F Do not interpolate path params, hash or search params into the `to` options. Use the `params`, `search`, and `hash` options instead.\n to: string\n // `params` is either an object of path params to interpolate into the `to` option or a function that supplies the previous params and allows you to return new ones. This is the only way to interpolate dynamic parameters into the final URL. Depending on the `from` and `to` route, you may need to supply none, some or all of the path params. TypeScript will notify you of the required params if there are any.\n params:\n | Record<string, unknown>\n | ((prevParams: Record<string, unknown>) => Record<string, unknown>)\n // `search` is either an object of query params or a function that supplies the previous search and allows you to return new ones. Depending on the `from` and `to` route, you may need to supply none, some or all of the query params. TypeScript will notify you of the required search params if there are any.\n search:\n | Record<string, unknown>\n | ((prevSearch: Record<string, unknown>) => Record<string, unknown>)\n // `hash` is either a string or a function that supplies the previous hash and allows you to return a new one.\n hash?: string | ((prevHash: string) => string)\n // `state` is either an object of state or a function that supplies the previous state and allows you to return a new one. State is stored in the history API and can be useful for passing data between routes that you do not want to permanently store in URL search params.\n state?:\n | Record<string, any>\n | ((prevState: Record<string, unknown>) => Record<string, unknown>)\n}\n```\n\n> \uD83E\uDDE0 Every route object has a `to` property, which can be used as the `to` for any navigation or route matching API. Where possible, this will allow you to avoid plain strings and use type-safe route references instead:\n\n```tsx\nimport { Route as aboutRoute } from './routes/about.tsx'\n\nfunction Comp() {\n return <Link to={aboutRoute.to}>About</Link>\n}\n```\n\n### `NavigateOptions` Interface\n\nThis is the core `NavigateOptions` interface that extends `ToOptions`. Any API that is actually performing a navigation will use this interface:\n\n```ts\nexport type NavigateOptions<\n TRouteTree extends AnyRoute = AnyRoute,\n TFrom extends RoutePaths<TRouteTree> | string = string,\n TTo extends string = '',\n> = ToOptions<TRouteTree, TFrom, TTo> & {\n // `replace` is a boolean that determines whether the navigation should replace the current history entry or push a new one.\n replace?: boolean\n // `resetScroll` is a boolean that determines whether scroll position will be reset to 0,0 after the location is committed to browser history.\n resetScroll?: boolean\n // `hashScrollIntoView` is a boolean or object that determines whether an id matching the hash will be scrolled into view after the location is committed to history.\n hashScrollIntoView?: boolean | ScrollIntoViewOptions\n // `viewTransition` is either a boolean or function that determines if and how the browser will call document.startViewTransition() when navigating.\n viewTransition?: boolean | ViewTransitionOptions\n // `ignoreBlocker` is a boolean that determines if navigation should ignore any blockers that might prevent it.\n ignoreBlocker?: boolean\n // `reloadDocument` is a boolean that determines if navigation to a route inside of router will trigger a full page load instead of the traditional SPA navigation.\n reloadDocument?: boolean\n // `href` is a string that can be used in place of `to` to navigate to a full built href, e.g. pointing to an external target.\n href?: string\n}\n```\n\n### `LinkOptions` Interface\n\nAnywhere an actual `<a>` tag the `LinkOptions` interface which extends `NavigateOptions` will be available:\n\n```tsx\nexport type LinkOptions<\n TRouteTree extends AnyRoute = AnyRoute,\n TFrom extends RoutePaths<TRouteTree> | string = string,\n TTo extends string = '',\n> = NavigateOptions<TRouteTree, TFrom, TTo> & {\n // The standard anchor tag target attribute\n target?: HTMLAnchorElement['target']\n // Defaults to `{ exact: false, includeHash: false }`\n activeOptions?: {\n exact?: boolean\n includeHash?: boolean\n includeSearch?: boolean\n explicitUndefined?: boolean\n }\n // If set, will preload the linked route on hover and cache it for this many milliseconds in hopes that the user will eventually navigate there.\n preload?: false | 'intent'\n // Delay intent preloading by this many milliseconds. If the intent exits before this delay, the preload will be cancelled.\n preloadDelay?: number\n // If true, will render the link without the href attribute\n disabled?: boolean\n}\n```\n\n## Navigation API\n\nWith relative navigation and all of the interfaces in mind now, let's talk about the different flavors of navigation API at your disposal:\n\n- The `<Link>` component\n - Generates an actual `<a>` tag with a valid `href` which can be click or even cmd/ctrl + clicked to open in a new tab\n- The `useNavigate()` hook\n - When possible, `Link` component should be used for navigation, but sometimes you need to navigate imperatively as a result of a side-effect. `useNavigate` returns a function that can be called to perform an immediate client-side navigation.\n- The `<Navigate>` component\n - Renders nothing and performs an immediate client-side navigation.\n- The `Router.navigate()` method\n - This is the most powerful navigation API in TanStack Router. Similar to `useNavigate`, it imperatively navigates, but is available everywhere you have access to your router.\n\n\u26A0\uFE0F None of these APIs are a replacement for server-side redirects. If you need to redirect a user immediately from one route to another before mounting your application, use a server-side redirect instead of a client-side navigation.\n\n## `<Link>` Component\n\nThe `Link` component is the most common way to navigate within an app. It renders an actual `<a>` tag with a valid `href` attribute which can be clicked or even cmd/ctrl + clicked to open in a new tab. It also supports any normal `<a>` attributes including `target` to open links in new windows, etc.\n\nIn addition to the [`LinkOptions`](#linkoptions-interface) interface, the `Link` component also supports the following props:\n\n```tsx\nexport type LinkProps<\n TFrom extends RoutePaths<RegisteredRouter['routeTree']> | string = string,\n TTo extends string = '',\n> = LinkOptions<RegisteredRouter['routeTree'], TFrom, TTo> & {\n // A function that returns additional props for the `active` state of this link. These props override other props passed to the link (`style`'s are merged, `className`'s are concatenated)\n activeProps?:\n | FrameworkHTMLAnchorTagAttributes\n | (() => FrameworkHTMLAnchorAttributes)\n // A function that returns additional props for the `inactive` state of this link. These props override other props passed to the link (`style`'s are merged, `className`'s are concatenated)\n inactiveProps?:\n | FrameworkHTMLAnchorAttributes\n | (() => FrameworkHTMLAnchorAttributes)\n}\n```\n\n### Absolute Links\n\nLet's make a simple static link!\n\n```tsx\nimport { Link } from '@tanstack/react-router'\n\nconst link = <Link to=\"/about\">About</Link>\n```\n\n### Dynamic Links\n\nDynamic links are links that have dynamic segments in them. For example, a link to a blog post might look like this:\n\n```tsx\nconst link = (\n <Link\n to=\"/blog/post/$postId\"\n params={{\n postId: 'my-first-blog-post',\n }}\n >\n Blog Post\n </Link>\n)\n```\n\nKeep in mind that normally dynamic segment params are `string` values, but they can also be any other type that you parse them to in your route options. Either way, the type will be checked at compile time to ensure that you are passing the correct type.\n\n### Relative Links\n\nBy default, all links are absolute unless a `from` route path is provided. This means that the above link will always navigate to the `/about` route regardless of what route you are currently on.\n\nRelative links can be combined with a `from` route path. If a from route path isn't provided, relative paths default to the current active location.\n\n> [!NOTE]\n> Keep in mind that when calling useNavigate as a method on the route, for example `Route.useNavigate`, then the `from` location is predefined to be the route it's called on.\n>\n> Another common pitfall is when using this in a pathless layout route, since the pathless layout route does not have an actual path, the `from` location is regarded as the parent of the pathless layout route. Hence relative routing will be resolved from this parent.\n\n```tsx\nconst postIdRoute = createRoute({\n path: '/blog/post/$postId',\n})\n\nconst link = (\n <Link from={postIdRoute.fullPath} to=\"../categories\">\n Categories\n </Link>\n)\n```\n\nAs seen above, it's common to provide the `route.fullPath` as the `from` route path. This is because the `route.fullPath` is a reference that will update if you refactor your application. However, sometimes it's not possible to import the route directly, in which case it's fine to provide the route path directly as a string. It will still get type-checked as per usual!\n\n### Special relative paths: `\".\"` and `\"..\"`\n\nQuite often you might want to reload the current location or another `from` path, for example, to rerun the loaders on the current and/or parent routes, or maybe navigate back to a parent route. This can be achieved by specifying a `to` route path of `\".\"` which will reload the current location or provided `from` path.\n\nAnother common need is to navigate one route back relative to the current location or another path. By specifying a `to` route path of `\"..\"` navigation will be resolved to the first parent route preceding the current location.\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n component: PostComponent,\n})\n\nfunction PostComponent() {\n return (\n <div>\n <Link to=\".\">Reload the current route of /posts/$postId</Link>\n <Link to=\"..\">Navigate back to /posts</Link>\n // the below are all equivalent\n <Link to=\"/posts\">Navigate back to /posts</Link>\n <Link from=\"/posts\" to=\".\">\n Navigate back to /posts\n </Link>\n // the below are all equivalent\n <Link to=\"/\">Navigate to root</Link>\n <Link from=\"/posts\" to=\"..\">\n Navigate to root\n </Link>\n </div>\n )\n}\n```\n\n### Search Param Links\n\nSearch params are a great way to provide additional context to a route. For example, you might want to provide a search query to a search page:\n\n```tsx\nconst link = (\n <Link\n to=\"/search\"\n search={{\n query: 'tanstack',\n }}\n >\n Search\n </Link>\n)\n```\n\nIt's also common to want to update a single search param without supplying any other information about the existing route. For example, you might want to update the page number of a search result:\n\n```tsx\nconst link = (\n <Link\n to=\".\"\n search={(prev) => ({\n ...prev,\n page: prev.page + 1,\n })}\n >\n Next Page\n </Link>\n)\n```\n\n### Search Param Type Safety\n\nSearch params are a highly dynamic state management mechanism, so it's important to ensure that you are passing the correct types to your search params. We'll see in a later section in detail how to validate and ensure search params typesafety, among other great features!\n\n### Hash Links\n\nHash links are a great way to link to a specific section of a page. For example, you might want to link to a specific section of a blog post:\n\n```tsx\nconst link = (\n <Link\n to=\"/blog/post/$postId\"\n params={{\n postId: 'my-first-blog-post',\n }}\n hash=\"section-1\"\n >\n Section 1\n </Link>\n)\n```\n\n### Navigating with Optional Parameters\n\nOptional path parameters provide flexible navigation patterns where you can include or omit parameters as needed. Optional parameters use the `{-$paramName}` syntax and offer fine-grained control over URL structure.\n\n#### Parameter Inheritance vs Removal\n\nWhen navigating with optional parameters, you have two main strategies:\n\n**Inheriting Current Parameters**\nUse `params: {}` to inherit all current route parameters:\n\n```tsx\n// Inherits current route parameters\n<Link to=\"/posts/{-$category}\" params={{}}>\n All Posts\n</Link>\n```\n\n**Removing Parameters** \nSet parameters to `undefined` to explicitly remove them:\n\n```tsx\n// Removes the category parameter\n<Link to=\"/posts/{-$category}\" params={{ category: undefined }}>\n All Posts\n</Link>\n```\n\n#### Basic Optional Parameter Navigation\n\n```tsx\n// Navigate with optional parameter\n<Link\n to=\"/posts/{-$category}\"\n params={{ category: 'tech' }}\n>\n Tech Posts\n</Link>\n\n// Navigate without optional parameter\n<Link\n to=\"/posts/{-$category}\"\n params={{ category: undefined }}\n>\n All Posts\n</Link>\n\n// Navigate using parameter inheritance\n<Link\n to=\"/posts/{-$category}\"\n params={{}}\n>\n Current Category\n</Link>\n```\n\n#### Function-Style Parameter Updates\n\nFunction-style parameter updates are particularly useful with optional parameters:\n\n```tsx\n// Remove a parameter using function syntax\n<Link\n to=\"/posts/{-$category}\"\n params={(prev) => ({ ...prev, category: undefined })}\n>\n Clear Category\n</Link>\n\n// Update a parameter while keeping others\n<Link\n to=\"/articles/{-$category}/{-$slug}\"\n params={(prev) => ({ ...prev, category: 'news' })}\n>\n News Articles\n</Link>\n\n// Conditionally set parameters\n<Link\n to=\"/posts/{-$category}\"\n params={(prev) => ({\n ...prev,\n category: someCondition ? 'tech' : undefined\n })}\n>\n Conditional Category\n</Link>\n```\n\n#### Multiple Optional Parameters\n\nWhen working with multiple optional parameters, you can mix and match which ones to include:\n\n```tsx\n// Navigate with some optional parameters\n<Link\n to=\"/posts/{-$category}/{-$slug}\"\n params={{ category: 'tech', slug: undefined }}\n>\n Tech Posts\n</Link>\n\n// Remove all optional parameters\n<Link\n to=\"/posts/{-$category}/{-$slug}\"\n params={{ category: undefined, slug: undefined }}\n>\n All Posts\n</Link>\n\n// Set multiple parameters\n<Link\n to=\"/posts/{-$category}/{-$slug}\"\n params={{ category: 'tech', slug: 'react-tips' }}\n>\n Specific Post\n</Link>\n```\n\n#### Mixed Required and Optional Parameters\n\nOptional parameters work seamlessly with required parameters:\n\n```tsx\n// Required 'id', optional 'tab'\n<Link\n to=\"/users/$id/{-$tab}\"\n params={{ id: '123', tab: 'settings' }}\n>\n User Settings\n</Link>\n\n// Remove optional parameter while keeping required\n<Link\n to=\"/users/$id/{-$tab}\"\n params={{ id: '123', tab: undefined }}\n>\n User Profile\n</Link>\n\n// Use function style with mixed parameters\n<Link\n to=\"/users/$id/{-$tab}\"\n params={(prev) => ({ ...prev, tab: 'notifications' })}\n>\n User Notifications\n</Link>\n```\n\n#### Advanced Optional Parameter Patterns\n\n**Prefix and Suffix Parameters**\nOptional parameters with prefix/suffix work with navigation:\n\n```tsx\n// Navigate to file with optional name\n<Link\n to=\"/files/prefix{-$name}.txt\"\n params={{ name: 'document' }}\n>\n Document File\n</Link>\n\n// Navigate to file without optional name\n<Link\n to=\"/files/prefix{-$name}.txt\"\n params={{ name: undefined }}\n>\n Default File\n</Link>\n```\n\n**All Optional Parameters**\nRoutes where all parameters are optional:\n\n```tsx\n// Navigate to specific date\n<Link\n to=\"/{-$year}/{-$month}/{-$day}\"\n params={{ year: '2023', month: '12', day: '25' }}\n>\n Christmas 2023\n</Link>\n\n// Navigate to partial date\n<Link\n to=\"/{-$year}/{-$month}/{-$day}\"\n params={{ year: '2023', month: '12', day: undefined }}\n>\n December 2023\n</Link>\n\n// Navigate to root with all parameters removed\n<Link\n to=\"/{-$year}/{-$month}/{-$day}\"\n params={{ year: undefined, month: undefined, day: undefined }}\n>\n Home\n</Link>\n```\n\n#### Navigation with Search Params and Optional Parameters\n\nOptional parameters work great in combination with search params:\n\n```tsx\n// Combine optional path params with search params\n<Link\n to=\"/posts/{-$category}\"\n params={{ category: 'tech' }}\n search={{ page: 1, sort: 'newest' }}\n>\n Tech Posts - Page 1\n</Link>\n\n// Remove path param but keep search params\n<Link\n to=\"/posts/{-$category}\"\n params={{ category: undefined }}\n search={(prev) => prev}\n>\n All Posts - Same Filters\n</Link>\n```\n\n#### Imperative Navigation with Optional Parameters\n\nAll the same patterns work with imperative navigation:\n\n```tsx\nfunction Component() {\n const navigate = useNavigate()\n\n const clearFilters = () => {\n navigate({\n to: '/posts/{-$category}/{-$tag}',\n params: { category: undefined, tag: undefined },\n })\n }\n\n const setCategory = (category: string) => {\n navigate({\n to: '/posts/{-$category}/{-$tag}',\n params: (prev) => ({ ...prev, category }),\n })\n }\n\n const applyFilters = (category?: string, tag?: string) => {\n navigate({\n to: '/posts/{-$category}/{-$tag}',\n params: { category, tag },\n })\n }\n}\n```\n\n### Active & Inactive Props\n\nThe `Link` component supports two additional props: `activeProps` and `inactiveProps`. These props are functions that return additional props for the `active` and `inactive` states of the link. All props other than styles and classes passed here will override the original props passed to `Link`. Any styles or classes passed are merged together.\n\nHere's an example:\n\n```tsx\nconst link = (\n <Link\n to=\"/blog/post/$postId\"\n params={{\n postId: 'my-first-blog-post',\n }}\n activeProps={{\n style: {\n fontWeight: 'bold',\n },\n }}\n >\n Section 1\n </Link>\n)\n```\n\n### The `data-status` attribute\n\nIn addition to the `activeProps` and `inactiveProps` props, the `Link` component also adds a `data-status` attribute to the rendered element when it is in an active state. This attribute will be `active` or `undefined` depending on the current state of the link. This can come in handy if you prefer to use data-attributes to style your links instead of props.\n\n### Active Options\n\nThe `Link` component comes with an `activeOptions` property that offers a few options of determining if a link is active or not. The following interface describes those options:\n\n```tsx\nexport interface ActiveOptions {\n // If true, the link will be active if the current route matches the `to` route path exactly (no children routes)\n // Defaults to `false`\n exact?: boolean\n // If true, the link will only be active if the current URL hash matches the `hash` prop\n // Defaults to `false`\n includeHash?: boolean // Defaults to false\n // If true, the link will only be active if the current URL search params inclusively match the `search` prop\n // Defaults to `true`\n includeSearch?: boolean\n // This modifies the `includeSearch` behavior.\n // If true, properties in `search` that are explicitly `undefined` must NOT be present in the current URL search params for the link to be active.\n // defaults to `false`\n explicitUndefined?: boolean\n}\n```\n\nBy default, it will check if the resulting **pathname** is a prefix of the current route. If any search params are provided, it will check that they _inclusively_ match those in the current location. Hashes are not checked by default.\n\nFor example, if you are on the `/blog/post/my-first-blog-post` route, the following links will be active:\n\n```tsx\nconst link1 = (\n <Link to=\"/blog/post/$postId\" params={{ postId: 'my-first-blog-post' }}>\n Blog Post\n </Link>\n)\nconst link2 = <Link to=\"/blog/post\">Blog Post</Link>\nconst link3 = <Link to=\"/blog\">Blog Post</Link>\n```\n\nHowever, the following links will not be active:\n\n```tsx\nconst link4 = (\n <Link to=\"/blog/post/$postId\" params={{ postId: 'my-second-blog-post' }}>\n Blog Post\n </Link>\n)\n```\n\nIt's common for some links to only be active if they are an exact match. A good example of this would be a link to the home page. In scenarios like these, you can pass the `exact: true` option:\n\n```tsx\nconst link = (\n <Link to=\"/\" activeOptions={{ exact: true }}>\n Home\n </Link>\n)\n```\n\nThis will ensure that the link is not active when you are a child route.\n\nA few more options to be aware of:\n\n- If you want to include the hash in your matching, you can pass the `includeHash: true` option\n- If you do **not** want to include the search params in your matching, you can pass the `includeSearch: false` option\n\n### Passing `isActive` to children\n\nThe `Link` component accepts a function for its children, allowing you to propagate its `isActive` property to children. For example, you could style a child component based on whether the parent link is active:\n\n```tsx\nconst link = (\n <Link to=\"/blog/post\">\n {({ isActive }) => {\n return (\n <>\n <span>My Blog Post</span>\n <icon className={isActive ? 'active' : 'inactive'} />\n </>\n )\n }}\n </Link>\n)\n```\n\n### Link Preloading\n\nThe `Link` component supports automatically preloading routes on intent (hovering or touchstart for now). This can be configured as a default in the router options (which we'll talk more about soon) or by passing a `preload='intent'` prop to the `Link` component. Here's an example:\n\n```tsx\nconst link = (\n <Link to=\"/blog/post/$postId\" preload=\"intent\">\n Blog Post\n </Link>\n)\n```\n\nWith preloading enabled and relatively quick asynchronous route dependencies (if any), this simple trick can increase the perceived performance of your application with very little effort.\n\nWhat's even better is that by using a cache-first library like `@tanstack/query`, preloaded routes will stick around and be ready for a stale-while-revalidate experience if the user decides to navigate to the route later on.\n\n### Link Preloading Delay\n\nAlong with preloading is a configurable delay which determines how long a user must hover over a link to trigger the intent-based preloading. The default delay is 50 milliseconds, but you can change this by passing a `preloadDelay` prop to the `Link` component with the number of milliseconds you'd like to wait:\n\n```tsx\nconst link = (\n <Link to=\"/blog/post/$postId\" preload=\"intent\" preloadDelay={100}>\n Blog Post\n </Link>\n)\n```\n\n## `useNavigate`\n\n> \u26A0\uFE0F Because of the `Link` component's built-in affordances around `href`, cmd/ctrl + click-ability, and active/inactive capabilities, it's recommended to use the `Link` component instead of `useNavigate` for anything the user can interact with (e.g. links, buttons). However, there are some cases where `useNavigate` is necessary to handle side-effect navigations (e.g. a successful async action that results in a navigation).\n\nThe `useNavigate` hook returns a `navigate` function that can be called to imperatively navigate. It's a great way to navigate to a route from a side-effect (e.g. a successful async action). Here's an example:\n\n```tsx\nfunction Component() {\n const navigate = useNavigate({ from: '/posts/$postId' })\n\n const handleSubmit = async (e: FrameworkFormEvent) => {\n e.preventDefault()\n\n const response = await fetch('/posts', {\n method: 'POST',\n body: JSON.stringify({ title: 'My First Post' }),\n })\n\n const { id: postId } = await response.json()\n\n if (response.ok) {\n navigate({ to: '/posts/$postId', params: { postId } })\n }\n }\n}\n```\n\n> \uD83E\uDDE0 As shown above, you can pass the `from` option to specify the route to navigate from in the hook call. While this is also possible to pass in the resulting `navigate` function each time you call it, it's recommended to pass it here to reduce on potential error and also not type as much!\n\n### `navigate` Options\n\nThe `navigate` function returned by `useNavigate` accepts the [`NavigateOptions` interface](#navigateoptions-interface)\n\n## `Navigate` Component\n\nOccasionally, you may find yourself needing to navigate immediately when a component mounts. Your first instinct might be to reach for `useNavigate` and an immediate side-effect (e.g. useEffect), but this is unnecessary. Instead, you can render the `Navigate` component to achieve the same result:\n\n```tsx\nfunction Component() {\n return <Navigate to=\"/posts/$postId\" params={{ postId: 'my-first-post' }} />\n}\n```\n\nThink of the `Navigate` component as a way to navigate to a route immediately when a component mounts. It's a great way to handle client-only redirects. It is _definitely not_ a substitute for handling server-aware redirects responsibly on the server.\n\n## `router.navigate`\n\nThe `router.navigate` method is the same as the `navigate` function returned by `useNavigate` and accepts the same [`NavigateOptions` interface](#navigateoptions-interface). Unlike the `useNavigate` hook, it is available anywhere your `router` instance is available and is thus a great way to navigate imperatively from anywhere in your application, including outside of your framework.\n\n## `useMatchRoute` and `<MatchRoute>`\n\nThe `useMatchRoute` hook and `<MatchRoute>` component are the same thing, but the hook is a bit more flexible. They both accept the standard navigation `ToOptions` interface either as options or props and return `true/false` if that route is currently matched. It also has a handy `pending` option that will return `true` if the route is currently pending (e.g. a route is currently transitioning to that route). This can be extremely useful for showing optimistic UI around where a user is navigating:\n\n```tsx\nfunction Component() {\n return (\n <div>\n <Link to=\"/users\">\n Users\n <MatchRoute to=\"/users\" pending>\n <Spinner />\n </MatchRoute>\n </Link>\n </div>\n )\n}\n```\n\nThe component version `<MatchRoute>` can also be used with a function as children to render something when the route is matched:\n\n```tsx\nfunction Component() {\n return (\n <div>\n <Link to=\"/users\">\n Users\n <MatchRoute to=\"/users\" pending>\n {(match) => {\n return <Spinner show={match} />\n }}\n </MatchRoute>\n </Link>\n </div>\n )\n}\n```\n\nThe hook version `useMatchRoute` returns a function that can be called programmatically to check if a route is matched:\n\n```tsx\nfunction Component() {\n const matchRoute = useMatchRoute()\n\n useEffect(() => {\n if (matchRoute({ to: '/users', pending: true })) {\n console.info('The /users route is matched and pending')\n }\n })\n\n return (\n <div>\n <Link to=\"/users\">Users</Link>\n </div>\n )\n}\n```\n\n---\n\nPhew! That's a lot of navigating! That said, hopefully you're feeling pretty good about getting around your application now. Let's move on!\n\n# Not Found Errors\n\n> \u26A0\uFE0F This page covers the newer `notFound` function and `notFoundComponent` API for handling not found errors. The `NotFoundRoute` route is deprecated and will be removed in a future release. See [Migrating from `NotFoundRoute`](#migrating-from-notfoundroute) for more information.\n\n## Overview\n\nThere are 2 uses for not-found errors in TanStack Router:\n\n- **Non-matching route paths**: When a path does not match any known route matching pattern **OR** when it partially matches a route, but with extra path segments\n - The **router** will automatically throw a not-found error when a path does not match any known route matching pattern\n - If the router's `notFoundMode` is set to `fuzzy`, the nearest parent route with a `notFoundComponent` will handle the error. If the router's `notFoundMode` is set to `root`, the root route will handle the error.\n - Examples:\n - Attempting to access `/users` when there is no `/users` route\n - Attempting to access `/posts/1/edit` when the route tree only handles `/posts/$postId`\n- **Missing resources**: When a resource cannot be found, such as a post with a given ID or any asynchronous data that is not available or does not exist\n - **You, the developer** must throw a not-found error when a resource cannot be found. This can be done in the `beforeLoad` or `loader` functions using the `notFound` utility.\n - Will be handled by the nearest parent route with a `notFoundComponent` (when `notFound` is called within `loader`) or the root route.\n - Examples:\n - Attempting to access `/posts/1` when the post with ID 1 does not exist\n - Attempting to access `/docs/path/to/document` when the document does not exist\n\nUnder the hood, both of these cases are implemented using the same `notFound` function and `notFoundComponent` API.\n\n## The `notFoundMode` option\n\nWhen TanStack Router encounters a **pathname** that doesn't match any known route pattern **OR** partially matches a route pattern but with extra trailing pathname segments, it will automatically throw a not-found error.\n\nDepending on the `notFoundMode` option, the router will handle these automatic errors differently::\n\n- [\"fuzzy\" mode](#notfoundmode-fuzzy) (default): The router will intelligently find the closest matching suitable route and display the `notFoundComponent`.\n- [\"root\" mode](#notfoundmode-root): All not-found errors will be handled by the root route's `notFoundComponent`, regardless of the nearest matching route.\n\n### `notFoundMode: 'fuzzy'`\n\nBy default, the router's `notFoundMode` is set to `fuzzy`, which indicates that if a pathname doesn't match any known route, the router will attempt to use the closest matching route with children/(an outlet) and a configured not found component.\n\n> **\u2753 Why is this the default?** Fuzzy matching to preserve as much parent layout as possible for the user gives them more context to navigate to a useful location based on where they thought they would arrive.\n\nThe nearest suitable route is found using the following criteria:\n\n- The route must have children and therefore an `Outlet` to render the `notFoundComponent`\n- The route must have a `notFoundComponent` configured or the router must have a `defaultNotFoundComponent` configured\n\nFor example, consider the following route tree:\n\n- `__root__` (has a `notFoundComponent` configured)\n - `posts` (has a `notFoundComponent` configured)\n - `$postId` (has a `notFoundComponent` configured)\n\nIf provided the path of `/posts/1/edit`, the following component structure will be rendered:\n\n- `<Root>`\n - `<Posts>`\n - `<Posts.notFoundComponent>`\n\nThe `notFoundComponent` of the `posts` route will be rendered because it is the **nearest suitable parent route with children (and therefore an outlet) and a `notFoundComponent` configured**.\n\n### `notFoundMode: 'root'`\n\nWhen `notFoundMode` is set to `root`, all not-found errors will be handled by the root route's `notFoundComponent` instead of bubbling up from the nearest fuzzy-matched route.\n\nFor example, consider the following route tree:\n\n- `__root__` (has a `notFoundComponent` configured)\n - `posts` (has a `notFoundComponent` configured)\n - `$postId` (has a `notFoundComponent` configured)\n\nIf provided the path of `/posts/1/edit`, the following component structure will be rendered:\n\n- `<Root>`\n - `<Root.notFoundComponent>`\n\nThe `notFoundComponent` of the `__root__` route will be rendered because the `notFoundMode` is set to `root`.\n\n## Configuring a route's `notFoundComponent`\n\nTo handle both types of not-found errors, you can attach a `notFoundComponent` to a route. This component will be rendered when a not-found error is thrown.\n\nFor example, configuring a `notFoundComponent` for a `/settings` route to handle non-existing settings pages:\n\n```tsx\nexport const Route = createFileRoute('/settings')({\n component: () => {\n return (\n <div>\n <p>Settings page</p>\n <Outlet />\n </div>\n )\n },\n notFoundComponent: () => {\n return <p>This setting page doesn't exist!</p>\n },\n})\n```\n\nOr configuring a `notFoundComponent` for a `/posts/$postId` route to handle posts that don't exist:\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params: { postId } }) => {\n const post = await getPost(postId)\n if (!post) throw notFound()\n return { post }\n },\n component: ({ post }) => {\n return (\n <div>\n <h1>{post.title}</h1>\n <p>{post.body}</p>\n </div>\n )\n },\n notFoundComponent: () => {\n return <p>Post not found!</p>\n },\n})\n```\n\n## Default Router-Wide Not Found Handling\n\nYou may want to provide a default not-found component for every route in your app with child routes.\n\n> Why only routes with children? **Leaf-node routes (routes without children) will never render an `Outlet` and therefore are not able to handle not-found errors.**\n\nTo do this, pass a `defaultNotFoundComponent` to the `createRouter` function:\n\n```tsx\nconst router = createRouter({\n defaultNotFoundComponent: () => {\n return (\n <div>\n <p>Not found!</p>\n <Link to=\"/\">Go home</Link>\n </div>\n )\n },\n})\n```\n\n## Throwing your own `notFound` errors\n\nYou can manually throw not-found errors in loader methods and components using the `notFound` function. This is useful when you need to signal that a resource cannot be found.\n\nThe `notFound` function works in a similar fashion to the `redirect` function. To cause a not-found error, you can **throw a `notFound()`**.\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params: { postId } }) => {\n // Returns `null` if the post doesn't exist\n const post = await getPost(postId)\n if (!post) {\n throw notFound()\n // Alternatively, you can make the notFound function throw:\n // notFound({ throw: true })\n }\n // Post is guaranteed to be defined here because we threw an error\n return { post }\n },\n})\n```\n\nThe not-found error above will be handled by the same route or nearest parent route that has either a `notFoundComponent` route option or the `defaultNotFoundComponent` router option configured.\n\nIf neither the route nor any suitable parent route is found to handle the error, the root route will handle it using TanStack Router's **extremely basic (and purposefully undesirable)** default not-found component that simply renders `<p>Not Found</p>`. It's highly recommended to either attach at least one `notFoundComponent` to the root route or configure a router-wide `defaultNotFoundComponent` to handle not-found errors.\n\n> \u26A0\uFE0F Throwing a notFound error in a beforeLoad method will always trigger the __root notFoundComponent. Since beforeLoad methods are run prior to the route loader methods, there is no guarantee that any required data for layouts have successfully loaded before the error is thrown.\n\n## Specifying Which Routes Handle Not Found Errors\n\nSometimes you may want to trigger a not-found on a specific parent route and bypass the normal not-found component propagation. To do this, pass in a route id to the `route` option in the `notFound` function.\n\n```tsx\n// _pathlessLayout.tsx\nexport const Route = createFileRoute('/_pathlessLayout')({\n // This will render\n notFoundComponent: () => {\n return <p>Not found (in _pathlessLayout)</p>\n },\n component: () => {\n return (\n <div>\n <p>This is a pathless layout route!</p>\n <Outlet />\n </div>\n )\n },\n})\n\n// _pathlessLayout/route-a.tsx\nexport const Route = createFileRoute('/_pathless/route-a')({\n loader: async () => {\n // This will make LayoutRoute handle the not-found error\n throw notFound({ routeId: '/_pathlessLayout' })\n // ^^^^^^^^^ This will autocomplete from the registered router\n },\n // This WILL NOT render\n notFoundComponent: () => {\n return <p>Not found (in _pathlessLayout/route-a)</p>\n },\n})\n```\n\n### Manually targeting the root route\n\nYou can also target the root route by passing the exported `rootRouteId` variable to the `notFound` function's `route` property:\n\n```tsx\nimport { rootRouteId } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params: { postId } }) => {\n const post = await getPost(postId)\n if (!post) throw notFound({ routeId: rootRouteId })\n return { post }\n },\n})\n```\n\n### Throwing Not Found Errors in Components\n\nYou can also throw not-found errors in components. However, **it is recommended to throw not-found errors in loader methods instead of components in order to correctly type loader data and prevent flickering.**\n\nTanStack Router exposes a `CatchNotFound` component similar to `CatchBoundary` that can be used to catch not-found errors in components and display UI accordingly.\n\n### Data Loading Inside `notFoundComponent`\n\n`notFoundComponent` is a special case when it comes to data loading. **`SomeRoute.useLoaderData` may not be defined depending on which route you are trying to access and where the not-found error gets thrown**. However, `Route.useParams`, `Route.useSearch`, `Route.useRouteContext`, etc. will return a defined value.\n\n**If you need to pass incomplete loader data to `notFoundComponent`,** pass the data via the `data` option in the `notFound` function and validate it in `notFoundComponent`.\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params: { postId } }) => {\n const post = await getPost(postId)\n if (!post)\n throw notFound({\n // Forward some data to the notFoundComponent\n // data: someIncompleteLoaderData\n })\n return { post }\n },\n // `data: unknown` is passed to the component via the `data` option when calling `notFound`\n notFoundComponent: ({ data }) => {\n // \u274C useLoaderData is not valid here: const { post } = Route.useLoaderData()\n\n // \u2705:\n const { postId } = Route.useParams()\n const search = Route.useSearch()\n const context = Route.useRouteContext()\n\n return <p>Post with id {postId} not found!</p>\n },\n})\n```\n\n## Usage With SSR\n\nSee [SSR guide](./ssr.md) for more information.\n\n## Migrating from `NotFoundRoute`\n\nThe `NotFoundRoute` API is deprecated in favor of `notFoundComponent`. The `NotFoundRoute` API will be removed in a future release.\n\n**The `notFound` function and `notFoundComponent` will not work when using `NotFoundRoute`.**\n\nThe main differences are:\n\n- `NotFoundRoute` is a route that requires an `<Outlet>` on its parent route to render. `notFoundComponent` is a component that can be attached to any route.\n- When using `NotFoundRoute`, you can't use layouts. `notFoundComponent` can be used with layouts.\n- When using `notFoundComponent`, path matching is strict. This means that if you have a route at `/post/$postId`, a not-found error will be thrown if you try to access `/post/1/2/3`. With `NotFoundRoute`, `/post/1/2/3` would match the `NotFoundRoute` and only render it if there is an `<Outlet>`.\n\nTo migrate from `NotFoundRoute` to `notFoundComponent`, you'll just need to make a few changes:\n\n```tsx\n// router.tsx\nimport { createRouter } from '@tanstack/react-router'\nimport { routeTree } from './routeTree.gen.'\n- import { notFoundRoute } from './notFoundRoute' // [!code --]\n\nexport const router = createRouter({\n routeTree,\n- notFoundRoute // [!code --]\n})\n\n// routes/__root.tsx\nimport { createRootRoute } from '@tanstack/react-router'\n\nexport const Route = createRootRoute({\n // ...\n+ notFoundComponent: () => { // [!code ++]\n+ return <p>Not found!</p> // [!code ++]\n+ } // [!code ++]\n})\n```\n\nImportant changes:\n\n- A `notFoundComponent` is added to the root route for global not-found handling.\n - You can also add a `notFoundComponent` to any other route in your route tree to handle not-found errors for that specific route.\n- The `notFoundComponent` does not support rendering an `<Outlet>`.\n\n# Outlets\n\nNested routing means that routes can be nested within other routes, including the way they render. So how do we tell our routes where to render this nested content?\n\n## The `Outlet` Component\n\nThe `Outlet` component is used to render the next potentially matching child route. `<Outlet />` doesn't take any props and can be rendered anywhere within a route's component tree. If there is no matching child route, `<Outlet />` will render `null`.\n\n> [!TIP]\n> If a route's `component` is left undefined, it will render an `<Outlet />` automatically.\n\nA great example is configuring the root route of your application. Let's give our root route a component that renders a title, then an `<Outlet />` for our top-level routes to render.\n\n```tsx\nimport { createRootRoute, Outlet } from '@tanstack/react-router'\n\nexport const Route = createRootRoute({\n component: RootComponent,\n})\n\nfunction RootComponent() {\n return (\n <div>\n <h1>My App</h1>\n <Outlet /> {/* This is where child routes will render */}\n </div>\n )\n}\n```\n\n# Parallel Routes\n\nWe haven't covered this yet. Stay tuned!\n\n# Path Params\n\nPath params are used to match a single segment (the text until the next `/`) and provide its value back to you as a **named** variable. They are defined by using the `$` character prefix in the path, followed by the key variable to assign it to. The following are valid path param paths:\n\n- `$postId`\n- `$name`\n- `$teamId`\n- `about/$name`\n- `team/$teamId`\n- `blog/$postId`\n\nBecause path param routes only match to the next `/`, child routes can be created to continue expressing hierarchy:\n\nLet's create a post route file that uses a path param to match the post ID:\n\n- `posts.$postId.tsx`\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params }) => {\n return fetchPost(params.postId)\n },\n})\n```\n\n## Path Params can be used by child routes\n\nOnce a path param has been parsed, it is available to all child routes. This means that if we define a child route to our `postRoute`, we can use the `postId` variable from the URL in the child route's path!\n\n## Path Params in Loaders\n\nPath params are passed to the loader as a `params` object. The keys of this object are the names of the path params, and the values are the values that were parsed out of the actual URL path. For example, if we were to visit the `/blog/123` URL, the `params` object would be `{ postId: '123' }`:\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params }) => {\n return fetchPost(params.postId)\n },\n})\n```\n\nThe `params` object is also passed to the `beforeLoad` option:\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n beforeLoad: async ({ params }) => {\n // do something with params.postId\n },\n})\n```\n\n## Path Params in Components\n\nIf we add a component to our `postRoute`, we can access the `postId` variable from the URL by using the route's `useParams` hook:\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n component: PostComponent,\n})\n\nfunction PostComponent() {\n const { postId } = Route.useParams()\n return <div>Post {postId}</div>\n}\n```\n\n> \uD83E\uDDE0 Quick tip: If your component is code-split, you can use the [getRouteApi function](./code-splitting.md#manually-accessing-route-apis-in-other-files-with-the-getrouteapi-helper) to avoid having to import the `Route` configuration to get access to the typed `useParams()` hook.\n\n## Path Params outside of Routes\n\nYou can also use the globally exported `useParams` hook to access any parsed path params from any component in your app. You'll need to pass the `strict: false` option to `useParams`, denoting that you want to access the params from an ambiguous location:\n\n```tsx\nfunction PostComponent() {\n const { postId } = useParams({ strict: false })\n return <div>Post {postId}</div>\n}\n```\n\n## Navigating with Path Params\n\nWhen navigating to a route with path params, TypeScript will require you to pass the params either as an object or as a function that returns an object of params.\n\nLet's see what an object style looks like:\n\n```tsx\nfunction Component() {\n return (\n <Link to=\"/blog/$postId\" params={{ postId: '123' }}>\n Post 123\n </Link>\n )\n}\n```\n\nAnd here's what a function style looks like:\n\n```tsx\nfunction Component() {\n return (\n <Link to=\"/blog/$postId\" params={(prev) => ({ ...prev, postId: '123' })}>\n Post 123\n </Link>\n )\n}\n```\n\nNotice that the function style is useful when you need to persist params that are already in the URL for other routes. This is because the function style will receive the current params as an argument, allowing you to modify them as needed and return the final params object.\n\n## Prefixes and Suffixes for Path Params\n\nYou can also use **prefixes** and **suffixes** with path params to create more complex routing patterns. This allows you to match specific URL structures while still capturing the dynamic segments.\n\nWhen using either prefixes or suffixes, you can define them by wrapping the path param in curly braces `{}` and placing the prefix or suffix before or after the variable name.\n\n### Defining Prefixes\n\nPrefixes are defined by placing the prefix text outside the curly braces before the variable name. For example, if you want to match a URL that starts with `post-` followed by a post ID, you can define it like this:\n\n```tsx\n// src/routes/posts/post-{$postId}.tsx\nexport const Route = createFileRoute('/posts/post-{$postId}')({\n component: PostComponent,\n})\n\nfunction PostComponent() {\n const { postId } = Route.useParams()\n // postId will be the value after 'post-'\n return <div>Post ID: {postId}</div>\n}\n```\n\nYou can even combines prefixes with wildcard routes to create more complex patterns:\n\n```tsx\n// src/routes/on-disk/storage-{$}\nexport const Route = createFileRoute('/on-disk/storage-{$postId}/$')({\n component: StorageComponent,\n})\n\nfunction StorageComponent() {\n const { _splat } = Route.useParams()\n // _splat, will be value after 'storage-'\n // i.e. my-drive/documents/foo.txt\n return <div>Storage Location: /{_splat}</div>\n}\n```\n\n### Defining Suffixes\n\nSuffixes are defined by placing the suffix text outside the curly braces after the variable name. For example, if you want to match a URL a filename that ends with `txt`, you can define it like this:\n\n```tsx\n// src/routes/files/{$fileName}txt\nexport const Route = createFileRoute('/files/{$fileName}.txt')({\n component: FileComponent,\n})\n\nfunction FileComponent() {\n const { fileName } = Route.useParams()\n // fileName will be the value before 'txt'\n return <div>File Name: {fileName}</div>\n}\n```\n\nYou can also combine suffixes with wildcards for more complex routing patterns:\n\n```tsx\n// src/routes/files/{$}[.]txt\nexport const Route = createFileRoute('/files/{$fileName}[.]txt')({\n component: FileComponent,\n})\n\nfunction FileComponent() {\n const { _splat } = Route.useParams()\n // _splat will be the value before '.txt'\n return <div>File Splat: {_splat}</div>\n}\n```\n\n### Combining Prefixes and Suffixes\n\nYou can combine both prefixes and suffixes to create very specific routing patterns. For example, if you want to match a URL that starts with `user-` and ends with `.json`, you can define it like this:\n\n```tsx\n// src/routes/users/user-{$userId}.json\nexport const Route = createFileRoute('/users/user-{$userId}.json')({\n component: UserComponent,\n})\n\nfunction UserComponent() {\n const { userId } = Route.useParams()\n // userId will be the value between 'user-' and '.json'\n return <div>User ID: {userId}</div>\n}\n```\n\nSimilar to the previous examples, you can also use wildcards with prefixes and suffixes. Go wild!\n\n## Optional Path Parameters\n\nOptional path parameters allow you to define route segments that may or may not be present in the URL. They use the `{-$paramName}` syntax and provide flexible routing patterns where certain parameters are optional.\n\n### Defining Optional Parameters\n\nOptional path parameters are defined using curly braces with a dash prefix: `{-$paramName}`\n\n```tsx\n// Single optional parameter\n// src/routes/posts/{-$category}.tsx\nexport const Route = createFileRoute('/posts/{-$category}')({\n component: PostsComponent,\n})\n\n// Multiple optional parameters\n// src/routes/posts/{-$category}/{-$slug}.tsx\nexport const Route = createFileRoute('/posts/{-$category}/{-$slug}')({\n component: PostComponent,\n})\n\n// Mixed required and optional parameters\n// src/routes/users/$id/{-$tab}.tsx\nexport const Route = createFileRoute('/users/$id/{-$tab}')({\n component: UserComponent,\n})\n```\n\n### How Optional Parameters Work\n\nOptional parameters create flexible URL patterns:\n\n- `/posts/{-$category}` matches both `/posts` and `/posts/tech`\n- `/posts/{-$category}/{-$slug}` matches `/posts`, `/posts/tech`, and `/posts/tech/hello-world`\n- `/users/$id/{-$tab}` matches `/users/123` and `/users/123/settings`\n\nWhen an optional parameter is not present in the URL, its value will be `undefined` in your route handlers and components.\n\n### Accessing Optional Parameters\n\nOptional parameters work exactly like regular parameters in your components, but their values may be `undefined`:\n\n```tsx\nfunction PostsComponent() {\n const { category } = Route.useParams()\n\n return <div>{category ? `Posts in ${category}` : 'All Posts'}</div>\n}\n```\n\n### Optional Parameters in Loaders\n\nOptional parameters are available in loaders and may be `undefined`:\n\n```tsx\nexport const Route = createFileRoute('/posts/{-$category}')({\n loader: async ({ params }) => {\n // params.category might be undefined\n return fetchPosts({ category: params.category })\n },\n})\n```\n\n### Optional Parameters in beforeLoad\n\nOptional parameters work in `beforeLoad` handlers as well:\n\n```tsx\nexport const Route = createFileRoute('/posts/{-$category}')({\n beforeLoad: async ({ params }) => {\n if (params.category) {\n // Validate category exists\n await validateCategory(params.category)\n }\n },\n})\n```\n\n### Advanced Optional Parameter Patterns\n\n#### With Prefix and Suffix\n\nOptional parameters support prefix and suffix patterns:\n\n```tsx\n// File route: /files/prefix{-$name}.txt\n// Matches: /files/prefix.txt and /files/prefixdocument.txt\nexport const Route = createFileRoute('/files/prefix{-$name}.txt')({\n component: FileComponent,\n})\n\nfunction FileComponent() {\n const { name } = Route.useParams()\n return <div>File: {name || 'default'}</div>\n}\n```\n\n#### All Optional Parameters\n\nYou can create routes where all parameters are optional:\n\n```tsx\n// Route: /{-$year}/{-$month}/{-$day}\n// Matches: /, /2023, /2023/12, /2023/12/25\nexport const Route = createFileRoute('/{-$year}/{-$month}/{-$day}')({\n component: DateComponent,\n})\n\nfunction DateComponent() {\n const { year, month, day } = Route.useParams()\n\n if (!year) return <div>Select a year</div>\n if (!month) return <div>Year: {year}</div>\n if (!day)\n return (\n <div>\n Month: {year}/{month}\n </div>\n )\n\n return (\n <div>\n Date: {year}/{month}/{day}\n </div>\n )\n}\n```\n\n#### Optional Parameters with Wildcards\n\nOptional parameters can be combined with wildcards for complex routing patterns:\n\n```tsx\n// Route: /docs/{-$version}/$\n// Matches: /docs/extra/path, /docs/v2/extra/path\nexport const Route = createFileRoute('/docs/{-$version}/$')({\n component: DocsComponent,\n})\n\nfunction DocsComponent() {\n const { version } = Route.useParams()\n const { _splat } = Route.useParams()\n\n return (\n <div>\n Version: {version || 'latest'}\n Path: {_splat}\n </div>\n )\n}\n```\n\n### Navigating with Optional Parameters\n\nWhen navigating to routes with optional parameters, you have fine-grained control over which parameters to include:\n\n```tsx\nfunction Navigation() {\n return (\n <div>\n {/* Navigate with optional parameter */}\n <Link to=\"/posts/{-$category}\" params={{ category: 'tech' }}>\n Tech Posts\n </Link>\n\n {/* Navigate without optional parameter */}\n <Link to=\"/posts/{-$category}\" params={{ category: undefined }}>\n All Posts\n </Link>\n\n {/* Navigate with multiple optional parameters */}\n <Link\n to=\"/posts/{-$category}/{-$slug}\"\n params={{ category: 'tech', slug: 'react-tips' }}\n >\n Specific Post\n </Link>\n </div>\n )\n}\n```\n\n### Type Safety with Optional Parameters\n\nTypeScript provides full type safety for optional parameters:\n\n```tsx\nfunction PostsComponent() {\n // TypeScript knows category might be undefined\n const { category } = Route.useParams() // category: string | undefined\n\n // Safe navigation\n const categoryUpper = category?.toUpperCase()\n\n return <div>{categoryUpper || 'All Categories'}</div>\n}\n\n// Navigation is type-safe and flexible\n<Link\n to=\"/posts/{-$category}\"\n params={{ category: 'tech' }} // \u2705 Valid - string\n>\n Tech Posts\n</Link>\n\n<Link\n to=\"/posts/{-$category}\"\n params={{ category: 123 }} // \u2705 Valid - number (auto-stringified)\n>\n Category 123\n</Link>\n```\n\n## Internationalization (i18n) with Optional Path Parameters\n\nOptional path parameters are excellent for implementing internationalization (i18n) routing patterns. You can use prefix patterns to handle multiple languages while maintaining clean, SEO-friendly URLs.\n\n### Prefix-based i18n\n\nUse optional language prefixes to support URLs like `/en/about`, `/fr/about`, or just `/about` (default language):\n\n```tsx\n// Route: /{-$locale}/about\nexport const Route = createFileRoute('/{-$locale}/about')({\n component: AboutComponent,\n})\n\nfunction AboutComponent() {\n const { locale } = Route.useParams()\n const currentLocale = locale || 'en' // Default to English\n\n const content = {\n en: { title: 'About Us', description: 'Learn more about our company.' },\n fr: {\n title: '\u00C0 Propos',\n description: 'En savoir plus sur notre entreprise.',\n },\n es: {\n title: 'Acerca de',\n description: 'Conoce m\u00E1s sobre nuestra empresa.',\n },\n }\n\n return (\n <div>\n <h1>{content[currentLocale]?.title}</h1>\n <p>{content[currentLocale]?.description}</p>\n </div>\n )\n}\n```\n\nThis pattern matches:\n\n- `/about` (default locale)\n- `/en/about` (explicit English)\n- `/fr/about` (French)\n- `/es/about` (Spanish)\n\n### Complex i18n Patterns\n\nCombine optional parameters for more sophisticated i18n routing:\n\n```tsx\n// Route: /{-$locale}/blog/{-$category}/$slug\nexport const Route = createFileRoute('/{-$locale}/blog/{-$category}/$slug')({\n beforeLoad: async ({ params }) => {\n const locale = params.locale || 'en'\n const category = params.category\n\n // Validate locale and category\n const validLocales = ['en', 'fr', 'es', 'de']\n if (locale && !validLocales.includes(locale)) {\n throw new Error('Invalid locale')\n }\n\n return { locale, category }\n },\n loader: async ({ params, context }) => {\n const { locale } = context\n const { slug, category } = params\n\n return fetchBlogPost({ slug, category, locale })\n },\n component: BlogPostComponent,\n})\n\nfunction BlogPostComponent() {\n const { locale, category, slug } = Route.useParams()\n const data = Route.useLoaderData()\n\n return (\n <article>\n <h1>{data.title}</h1>\n <p>\n Category: {category || 'All'} | Language: {locale || 'en'}\n </p>\n <div>{data.content}</div>\n </article>\n )\n}\n```\n\nThis supports URLs like:\n\n- `/blog/tech/my-post` (default locale, tech category)\n- `/fr/blog/my-post` (French, no category)\n- `/en/blog/tech/my-post` (explicit English, tech category)\n- `/es/blog/tecnologia/mi-post` (Spanish, Spanish category)\n\n### Language Navigation\n\nCreate language switchers using optional i18n parameters with function-style params:\n\n```tsx\nfunction LanguageSwitcher() {\n const currentParams = useParams({ strict: false })\n\n const languages = [\n { code: 'en', name: 'English' },\n { code: 'fr', name: 'Fran\u00E7ais' },\n { code: 'es', name: 'Espa\u00F1ol' },\n ]\n\n return (\n <div className=\"language-switcher\">\n {languages.map(({ code, name }) => (\n <Link\n key={code}\n to=\"/{-$locale}/blog/{-$category}/$slug\"\n params={(prev) => ({\n ...prev,\n locale: code === 'en' ? undefined : code, // Remove 'en' for clean URLs\n })}\n className={currentParams.locale === code ? 'active' : ''}\n >\n {name}\n </Link>\n ))}\n </div>\n )\n}\n```\n\nYou can also create more sophisticated language switching logic:\n\n```tsx\nfunction AdvancedLanguageSwitcher() {\n const currentParams = useParams({ strict: false })\n\n const handleLanguageChange = (newLocale: string) => {\n return (prev: any) => {\n // Preserve all existing params but update locale\n const updatedParams = { ...prev }\n\n if (newLocale === 'en') {\n // Remove locale for clean English URLs\n delete updatedParams.locale\n } else {\n updatedParams.locale = newLocale\n }\n\n return updatedParams\n }\n }\n\n return (\n <div className=\"language-switcher\">\n <Link\n to=\"/{-$locale}/blog/{-$category}/$slug\"\n params={handleLanguageChange('fr')}\n >\n Fran\u00E7ais\n </Link>\n\n <Link\n to=\"/{-$locale}/blog/{-$category}/$slug\"\n params={handleLanguageChange('es')}\n >\n Espa\u00F1ol\n </Link>\n\n <Link\n to=\"/{-$locale}/blog/{-$category}/$slug\"\n params={handleLanguageChange('en')}\n >\n English\n </Link>\n </div>\n )\n}\n```\n\n### Advanced i18n with Optional Parameters\n\nOrganize i18n routes using optional parameters for flexible locale handling:\n\n```tsx\n// Route structure:\n// routes/\n// {-$locale}/\n// index.tsx // /, /en, /fr\n// about.tsx // /about, /en/about, /fr/about\n// blog/\n// index.tsx // /blog, /en/blog, /fr/blog\n// $slug.tsx // /blog/post, /en/blog/post, /fr/blog/post\n\n// routes/{-$locale}/index.tsx\nexport const Route = createFileRoute('/{-$locale}/')({\n component: HomeComponent,\n})\n\nfunction HomeComponent() {\n const { locale } = Route.useParams()\n const isRTL = ['ar', 'he', 'fa'].includes(locale || '')\n\n return (\n <div dir={isRTL ? 'rtl' : 'ltr'}>\n <h1>Welcome ({locale || 'en'})</h1>\n {/* Localized content */}\n </div>\n )\n}\n\n// routes/{-$locale}/about.tsx\nexport const Route = createFileRoute('/{-$locale}/about')({\n component: AboutComponent,\n})\n```\n\n### SEO and Canonical URLs\n\nHandle SEO for i18n routes properly:\n\n```tsx\nexport const Route = createFileRoute('/{-$locale}/products/$id')({\n component: ProductComponent,\n head: ({ params, loaderData }) => {\n const locale = params.locale || 'en'\n const product = loaderData\n\n return {\n title: product.title[locale] || product.title.en,\n meta: [\n {\n name: 'description',\n content: product.description[locale] || product.description.en,\n },\n {\n property: 'og:locale',\n content: locale,\n },\n ],\n links: [\n // Canonical URL (always use default locale format)\n {\n rel: 'canonical',\n href: `https://example.com/products/${params.id}`,\n },\n // Alternate language versions\n {\n rel: 'alternate',\n hreflang: 'en',\n href: `https://example.com/products/${params.id}`,\n },\n {\n rel: 'alternate',\n hreflang: 'fr',\n href: `https://example.com/fr/products/${params.id}`,\n },\n {\n rel: 'alternate',\n hreflang: 'es',\n href: `https://example.com/es/products/${params.id}`,\n },\n ],\n }\n },\n})\n```\n\n### Type Safety for i18n\n\nEnsure type safety for your i18n implementations:\n\n```tsx\n// Define supported locales\ntype Locale = 'en' | 'fr' | 'es' | 'de'\n\n// Type-safe locale validation\nfunction validateLocale(locale: string | undefined): locale is Locale {\n return ['en', 'fr', 'es', 'de'].includes(locale as Locale)\n}\n\nexport const Route = createFileRoute('/{-$locale}/shop/{-$category}')({\n beforeLoad: async ({ params }) => {\n const { locale } = params\n\n // Type-safe locale validation\n if (locale && !validateLocale(locale)) {\n throw redirect({\n to: '/shop/{-$category}',\n params: { category: params.category },\n })\n }\n\n return {\n locale: (locale as Locale) || 'en',\n isDefaultLocale: !locale || locale === 'en',\n }\n },\n component: ShopComponent,\n})\n\nfunction ShopComponent() {\n const { locale, category } = Route.useParams()\n const { isDefaultLocale } = Route.useRouteContext()\n\n // TypeScript knows locale is Locale | undefined\n // and we have validated it in beforeLoad\n\n return (\n <div>\n <h1>Shop {category ? `- ${category}` : ''}</h1>\n <p>Language: {locale || 'en'}</p>\n {!isDefaultLocale && (\n <Link to=\"/shop/{-$category}\" params={{ category }}>\n View in English\n </Link>\n )}\n </div>\n )\n}\n```\n\nOptional path parameters provide a powerful and flexible foundation for implementing internationalization in your TanStack Router applications. Whether you prefer prefix-based or combined approaches, you can create clean, SEO-friendly URLs while maintaining excellent developer experience and type safety.\n\n## Allowed Characters\n\nBy default, path params are escaped with `encodeURIComponent`. If you want to allow other valid URI characters (e.g. `@` or `+`), you can specify that in your [RouterOptions](../api/router/RouterOptionsType.md#pathparamsallowedcharacters-property).\n\nExample usage:\n\n```tsx\nconst router = createRouter({\n // ...\n pathParamsAllowedCharacters: ['@'],\n})\n```\n\nThe following is the list of accepted allowed characters:\n\n- `;`\n- `:`\n- `@`\n- `&`\n- `=`\n- `+`\n- `$`\n- `,`\n\n# Preloading\n\nPreloading in TanStack Router is a way to load a route before the user actually navigates to it. This is useful for routes that are likely to be visited by the user next. For example, if you have a list of posts and the user is likely to click on one of them, you can preload the post route so that it's ready to go when the user clicks on it.\n\n## Supported Preloading Strategies\n\n- Intent\n - Preloading by **\"intent\"** works by using hover and touch start events on `<Link>` components to preload the dependencies for the destination route.\n - This strategy is useful for preloading routes that the user is likely to visit next.\n- Viewport Visibility\n - Preloading by **\"viewport**\" works by using the Intersection Observer API to preload the dependencies for the destination route when the `<Link>` component is in the viewport.\n - This strategy is useful for preloading routes that are below the fold or off-screen.\n- Render\n - Preloading by **\"render\"** works by preloading the dependencies for the destination route as soon as the `<Link>` component is rendered in the DOM.\n - This strategy is useful for preloading routes that are always needed.\n\n## How long does preloaded data stay in memory?\n\nPreloaded route matches are temporarily cached in memory with a few important caveats:\n\n- **Unused preloaded data is removed after 30 seconds by default.** This can be configured by setting the `defaultPreloadMaxAge` option on your router.\n- **Obviously, when a route is loaded, its preloaded version is promoted to the router's normal pending matches state.**\n\nIf you need more control over preloading, caching and/or garbage collection of preloaded data, you should use an external caching library like [TanStack Query](https://tanstack.com/query).\n\nThe simplest way to preload routes for your application is to set the `defaultPreload` option to `intent` for your entire router:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n // ...\n defaultPreload: 'intent',\n})\n```\n\nThis will turn on `intent` preloading by default for all `<Link>` components in your application. You can also set the `preload` prop on individual `<Link>` components to override the default behavior.\n\n## Preload Delay\n\nBy default, preloading will start after **50ms** of the user hovering or touching a `<Link>` component. You can change this delay by setting the `defaultPreloadDelay` option on your router:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n // ...\n defaultPreloadDelay: 100,\n})\n```\n\nYou can also set the `preloadDelay` prop on individual `<Link>` components to override the default behavior on a per-link basis.\n\n## Built-in Preloading & `preloadStaleTime`\n\nIf you're using the built-in loaders, you can control how long preloaded data is considered fresh until another preload is triggered by setting either `routerOptions.defaultPreloadStaleTime` or `routeOptions.preloadStaleTime` to a number of milliseconds. **By default, preloaded data is considered fresh for 30 seconds.**.\n\nTo change this, you can set the `defaultPreloadStaleTime` option on your router:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n // ...\n defaultPreloadStaleTime: 10_000,\n})\n```\n\nOr, you can use the `routeOptions.preloadStaleTime` option on individual routes:\n\n```tsx\n// src/routes/posts.$postId.tsx\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params }) => fetchPost(params.postId),\n // Preload the route again if the preload cache is older than 10 seconds\n preloadStaleTime: 10_000,\n})\n```\n\n## Preloading with External Libraries\n\nWhen integrating external caching libraries like React Query, which have their own mechanisms for determining stale data, you may want to override the default preloading and stale-while-revalidate logic of TanStack Router. These libraries often use options like staleTime to control the freshness of data.\n\nTo customize the preloading behavior in TanStack Router and fully leverage your external library's caching strategy, you can bypass the built-in caching by setting routerOptions.defaultPreloadStaleTime or routeOptions.preloadStaleTime to 0. This ensures that all preloads are marked as stale internally, and loaders are always invoked, allowing your external library, such as React Query, to manage data loading and caching.\n\nFor example:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n // ...\n defaultPreloadStaleTime: 0,\n})\n```\n\nThis would then allow you, for instance, to use an option like React Query's `staleTime` to control the freshness of your preloads.\n\n## Preloading Manually\n\nIf you need to manually preload a route, you can use the router's `preloadRoute` method. It accepts a standard TanStack `NavigateOptions` object and returns a promise that resolves when the route is preloaded.\n\n```tsx\nfunction Component() {\n const router = useRouter()\n\n useEffect(() => {\n async function preload() {\n try {\n const matches = await router.preloadRoute({\n to: postRoute,\n params: { id: 1 },\n })\n } catch (err) {\n // Failed to preload route\n }\n }\n\n preload()\n }, [router])\n\n return <div />\n}\n```\n\nIf you need to preload only the JS chunk of a route, you can use the router's `loadRouteChunk` method. It accepts a route object and returns a promise that resolves when the route chunk is loaded.\n\n```tsx\nfunction Component() {\n const router = useRouter()\n\n useEffect(() => {\n async function preloadRouteChunks() {\n try {\n const postsRoute = router.routesByPath['/posts']\n await Promise.all([\n router.loadRouteChunk(router.routesByPath['/']),\n router.loadRouteChunk(postsRoute),\n router.loadRouteChunk(postsRoute.parentRoute),\n ])\n } catch (err) {\n // Failed to preload route chunk\n }\n }\n\n preloadRouteChunks()\n }, [router])\n\n return <div />\n}\n```\n\n# Render Optimizations\n\nTanStack Router includes several optimizations to ensure your components only re-render when necessary. These optimizations include:\n\n## structural sharing\n\nTanStack Router uses a technique called \"structural sharing\" to preserve as many references as possible between re-renders, which is particularly useful for state stored in the URL, such as search parameters.\n\nFor example, consider a `details` route with two search parameters, `foo` and `bar`, accessed like this:\n\n```tsx\nconst search = Route.useSearch()\n```\n\nWhen only `bar` is changed by navigating from `/details?foo=f1&bar=b1` to `/details?foo=f1&bar=b2`, `search.foo` will be referentially stable and only `search.bar` will be replaced.\n\n## fine-grained selectors\n\nYou can access and subscribe to the router state using various hooks like `useRouterState`, `useSearch`, and others. If you only want a specific component to re-render when a particular subset of the router state such as a subset of the search parameters changes, you can use partial subscriptions with the `select` property.\n\n```tsx\n// component won't re-render when `bar` changes\nconst foo = Route.useSearch({ select: ({ foo }) => foo })\n```\n\n### structural sharing with fine-grained selectors\n\nThe `select` function can perform various calculations on the router state, allowing you to return different types of values, such as objects. For example:\n\n```tsx\nconst result = Route.useSearch({\n select: (search) => {\n return {\n foo: search.foo,\n hello: `hello ${search.foo}`,\n }\n },\n})\n```\n\nAlthough this works, it will cause your component to re-render each time, since `select` is now returning a new object each time it\u2019s called.\n\nYou can avoid this re-rendering issue by using \"structural sharing\" as described above. By default, structural sharing is turned off to maintain backward compatibility, but this may change in v2.\n\nTo enable structural sharing for fine grained selectors, you have two options:\n\n#### Enable it by default in the router options:\n\n```tsx\nconst router = createRouter({\n routeTree,\n defaultStructuralSharing: true,\n})\n```\n\n#### Enable it per hook usage as shown here:\n\n```tsx\nconst result = Route.useSearch({\n select: (search) => {\n return {\n foo: search.foo,\n hello: `hello ${search.foo}`,\n }\n },\n structuralSharing: true,\n})\n```\n\n> [!IMPORTANT]\n> Structural sharing only works with JSON-compatible data. This means you cannot use `select` to return items like class instances if structural sharing is enabled.\n\nIn line with TanStack Router's type-safe design, TypeScript will raise an error if you attempt the following:\n\n```tsx\nconst result = Route.useSearch({\n select: (search) => {\n return {\n date: new Date(),\n }\n },\n structuralSharing: true,\n})\n```\n\nIf structural sharing is enabled by default in the router options, you can prevent this error by setting `structuralSharing: false`.\n\n# Route Masking\n\nRoute masking is a way to mask the actual URL of a route that gets persisted to the browser's history and URL bar. This is useful for scenarios where you want to show a different URL than the one that is actually being navigated to and then falling back to the displayed URL when it is shared and (optionally) when the page is reloaded. Here's a few examples:\n\n- Navigating to a modal route like `/photo/5/modal`, but masking the actual URL as `/photos/5`\n- Navigating to a modal route like `/post/5/comments`, but masking the actual URL as `/posts/5`\n- Navigating to a route with the search param `?showLogin=true`, but masking the URL to _not_ contain the search param\n- Navigating to a route with the search param `?modal=settings`, but masking the URL as `/settings'\n\nEach of these scenarios can be achieved with route masking and even extended to support more advanced patterns like [parallel routes](./parallel-routes.md).\n\n## How does route masking work?\n\n> [!IMPORTANT]\n> You **do not** need to understand how route masking works in order to use it. This section is for those who are curious about how it works under the hood. Skip to [How do I use route masking?](#how-do-i-use-route-masking) to learn how to use it!.\n\nRoute masking utilizes the `location.state` API to store the desired runtime location inside of the location that will get written to the URL. It stores this runtime location under the `__tempLocation` state property:\n\n```tsx\nconst location = {\n pathname: '/photos/5',\n search: '',\n hash: '',\n state: {\n key: 'wesdfs',\n __tempKey: 'sadfasd',\n __tempLocation: {\n pathname: '/photo/5/modal',\n search: '',\n hash: '',\n state: {},\n },\n },\n}\n```\n\nWhen the router parses a location from history with the `location.state.__tempLocation` property, it will use that location instead of the one that was parsed from the URL. This allows you to navigate to a route like `/photos/5` and have the router actually navigate to `/photo/5/modal` instead. When this happens, the history location is saved back into the `location.maskedLocation` property, just in case we need to know what the **actual URL** is. One example of where this is used is in the Devtools where we detect if a route is masked and show the actual URL instead of the masked one!\n\nRemember, you don't need to worry about any of this. It's all handled for you automatically under the hood!\n\n## How do I use route masking?\n\nRoute masking is a simple API that can be used in 2 ways:\n\n- Imperatively via the `mask` option available on the `<Link>` and `navigate()` APIs\n- Declaratively via the Router's `routeMasks` option\n\nWhen using either route masking APIs, the `mask` option accepts the same navigation object that the `<Link>` and `navigate()` APIs accept. This means you can use the same `to`, `replace`, `state`, and `search` options that you're already familiar with. The only difference is that the `mask` option will be used to mask the URL of the route being navigated to.\n\n> \uD83E\uDDE0 The mask option is also **type-safe**! This means that if you're using TypeScript, you'll get type errors if you try to pass an invalid navigation object to the `mask` option. Booyah!\n\n### Imperative route masking\n\nThe `<Link>` and `navigate()` APIs both accept a `mask` option that can be used to mask the URL of the route being navigated to. Here's an example of using it with the `<Link>` component:\n\n```tsx\n<Link\n to=\"/photos/$photoId/modal\"\n params={{ photoId: 5 }}\n mask={{\n to: '/photos/$photoId',\n params: {\n photoId: 5,\n },\n }}\n>\n Open Photo\n</Link>\n```\n\nAnd here's an example of using it with the `navigate()` API:\n\n```tsx\nconst navigate = useNavigate()\n\nfunction onOpenPhoto() {\n navigate({\n to: '/photos/$photoId/modal',\n params: { photoId: 5 },\n mask: {\n to: '/photos/$photoId',\n params: {\n photoId: 5,\n },\n },\n })\n}\n```\n\n### Declarative route masking\n\nIn addition to the imperative API, you can also use the Router's `routeMasks` option to declaratively mask routes. Instead of needing to pass the `mask` option to every `<Link>` or `navigate()` call, you can instead create a route mask on the Router to mask routes that match a certain pattern. Here's an example of the same route mask from above, but using the `routeMasks` option instead:\n\n// Use the following for the example below\n\n```tsx\nimport { createRouteMask } from '@tanstack/react-router'\n\nconst photoModalToPhotoMask = createRouteMask({\n routeTree,\n from: '/photos/$photoId/modal',\n to: '/photos/$photoId',\n params: (prev) => ({\n photoId: prev.photoId,\n }),\n})\n\nconst router = createRouter({\n routeTree,\n routeMasks: [photoModalToPhotoMask],\n})\n```\n\nWhen creating a route mask, you'll need to pass 1 argument with at least:\n\n- `routeTree` - The route tree that the route mask will be applied to\n- `from` - The route ID that the route mask will be applied to\n- `...navigateOptions` - The standard `to`, `search`, `params`, `replace`, etc options that the `<Link>` and `navigate()` APIs accept\n\n> \uD83E\uDDE0 The `createRouteMask` option is also **type-safe**! This means that if you're using TypeScript, you'll get type errors if you try to pass an invalid route mask to the `routeMasks` option.\n\n## Unmasking when sharing the URL\n\nURLs are automatically unmasked when they are shared since as soon as a URL is detached from your browsers local history stack, the URL masking data is no longer available. Essentially, as soon as you copy and paste a URL out of your history, its masking data is lost... after all, that's the point of masking a URL!\n\n## Local Unmasking Defaults\n\n**By default, URLs are not unmasked when the page is reloaded locally**. Masking data is stored in the `location.state` property of the history location, so as long as the history location is still in memory in your history stack, the masking data will be available and the URL will continue to be masked.\n\n## Unmasking on page reload\n\n**As stated above, URLs are not unmasked when the page is reloaded by default**.\n\nIf you want to unmask a URL locally when the page is reloaded, you have 3 options, each overriding the previous one in priority if passed:\n\n- Set the Router's default `unmaskOnReload` option to `true`\n- Return the `unmaskOnReload: true` option from the masking function when creating a route mask with `createRouteMask()`\n- Pass the `unmaskOnReload: true` option to the `<Link`> component or `navigate()` API\n\n# Router Context\n\nTanStack Router's router context is a very powerful tool that can be used for dependency injection among many other things. Aptly named, the router context is passed through the router and down through each matching route. At each route in the hierarchy, the context can be modified or added to. Here's a few ways you might use the router context practically:\n\n- Dependency Injection\n - You can supply dependencies (e.g. a loader function, a data fetching client, a mutation service) which the route and all child routes can access and use without importing or creating directly.\n- Breadcrumbs\n - While the main context object for each route is merged as it descends, each route's unique context is also stored making it possible to attach breadcrumbs or methods to each route's context.\n- Dynamic meta tag management\n - You can attach meta tags to each route's context and then use a meta tag manager to dynamically update the meta tags on the page as the user navigates the site.\n\nThese are just suggested uses of the router context. You can use it for whatever you want!\n\n## Typed Router Context\n\nLike everything else, the root router context is strictly typed. This type can be augmented via any route's `beforeLoad` option as it is merged down the route match tree. To constrain the type of the root router context, you must use the `createRootRouteWithContext<YourContextTypeHere>()(routeOptions)` function to create a new router context instead of the `createRootRoute()` function to create your root route. Here's an example:\n\n```tsx\nimport {\n createRootRouteWithContext,\n createRouter,\n} from '@tanstack/react-router'\n\ninterface MyRouterContext {\n user: User\n}\n\n// Use the routerContext to create your root route\nconst rootRoute = createRootRouteWithContext<MyRouterContext>()({\n component: App,\n})\n\nconst routeTree = rootRoute.addChildren([\n // ...\n])\n\n// Use the routerContext to create your router\nconst router = createRouter({\n routeTree,\n})\n```\n\n> [!TIP]\n> `MyRouterContext` only needs to contain content that will be passed directly to `createRouter` below. All other context added in `beforeLoad` will be inferred.\n\n## Passing the initial Router Context\n\nThe router context is passed to the router at instantiation time. You can pass the initial router context to the router via the `context` option:\n\n> [!TIP]\n> If your context has any required properties, you will see a TypeScript error if you don't pass them in the initial router context. If all of your context properties are optional, you will not see a TypeScript error and passing the context will be optional. If you don't pass a router context, it defaults to `{}`.\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\n// Use the routerContext you created to create your router\nconst router = createRouter({\n routeTree,\n context: {\n user: {\n id: '123',\n name: 'John Doe',\n },\n },\n})\n```\n\n### Invalidating the Router Context\n\nIf you need to invalidate the context state you are passing into the router, you can call the `invalidate` method to tell the router to recompute the context. This is useful when you need to update the context state and have the router recompute the context for all routes.\n\n```tsx\nfunction useAuth() {\n const router = useRouter()\n const [user, setUser] = useState<User | null>(null)\n\n useEffect(() => {\n const unsubscribe = auth.onAuthStateChanged((user) => {\n setUser(user)\n router.invalidate()\n })\n\n return unsubscribe\n }, [])\n\n return user\n}\n```\n\n## Using the Router Context\n\nOnce you have defined the router context type, you can use it in your route definitions:\n\n```tsx\n// src/routes/todos.tsx\nexport const Route = createFileRoute('/todos')({\n component: Todos,\n loader: ({ context }) => fetchTodosByUserId(context.user.id),\n})\n```\n\nYou can even inject data fetching and mutation implementations themselves! In fact, this is highly recommended \uD83D\uDE1C\n\nLet's try this with a simple function to fetch some todos:\n\n```tsx\nconst fetchTodosByUserId = async ({ userId }) => {\n const response = await fetch(`/api/todos?userId=${userId}`)\n const data = await response.json()\n return data\n}\n\nconst router = createRouter({\n routeTree: rootRoute,\n context: {\n userId: '123',\n fetchTodosByUserId,\n },\n})\n```\n\nThen, in your route:\n\n```tsx\n// src/routes/todos.tsx\nexport const Route = createFileRoute('/todos')({\n component: Todos,\n loader: ({ context }) => context.fetchTodosByUserId(context.userId),\n})\n```\n\n### How about an external data fetching library?\n\n```tsx\nimport {\n createRootRouteWithContext,\n createRouter,\n} from '@tanstack/react-router'\n\ninterface MyRouterContext {\n queryClient: QueryClient\n}\n\nconst rootRoute = createRootRouteWithContext<MyRouterContext>()({\n component: App,\n})\n\nconst queryClient = new QueryClient()\n\nconst router = createRouter({\n routeTree: rootRoute,\n context: {\n queryClient,\n },\n})\n```\n\nThen, in your route:\n\n```tsx\n// src/routes/todos.tsx\nexport const Route = createFileRoute('/todos')({\n component: Todos,\n loader: async ({ context }) => {\n await context.queryClient.ensureQueryData({\n queryKey: ['todos', { userId: user.id }],\n queryFn: fetchTodos,\n })\n },\n})\n```\n\n## How about using React Context/Hooks?\n\nWhen trying to use React Context or Hooks in your route's `beforeLoad` or `loader` functions, it's important to remember React's [Rules of Hooks](https://react.dev/reference/rules/rules-of-hooks). You can't use hooks in a non-React function, so you can't use hooks in your `beforeLoad` or `loader` functions.\n\nSo, how do we use React Context or Hooks in our route's `beforeLoad` or `loader` functions? We can use the router context to pass down the React Context or Hooks to our route's `beforeLoad` or `loader` functions.\n\nLet's look at the setup for an example, where we pass down a `useNetworkStrength` hook to our route's `loader` function:\n\n- `src/routes/__root.tsx`\n\n```tsx\n// First, make sure the context for the root route is typed\nimport { createRootRouteWithContext } from '@tanstack/react-router'\nimport { useNetworkStrength } from '@/hooks/useNetworkStrength'\n\ninterface MyRouterContext {\n networkStrength: ReturnType<typeof useNetworkStrength>\n}\n\nexport const Route = createRootRouteWithContext<MyRouterContext>()({\n component: App,\n})\n```\n\nIn this example, we'd instantiate the hook before rendering the router using the `<RouterProvider />`. This way, the hook would be called in React-land, therefore adhering to the Rules of Hooks.\n\n- `src/router.tsx`\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nimport { routeTree } from './routeTree.gen'\n\nexport const router = createRouter({\n routeTree,\n context: {\n networkStrength: undefined!, // We'll set this in React-land\n },\n})\n```\n\n- `src/main.tsx`\n\n```tsx\nimport { RouterProvider } from '@tanstack/react-router'\nimport { router } from './router'\n\nimport { useNetworkStrength } from '@/hooks/useNetworkStrength'\n\nfunction App() {\n const networkStrength = useNetworkStrength()\n // Inject the returned value from the hook into the router context\n return <RouterProvider router={router} context={{ networkStrength }} />\n}\n\n// ...\n```\n\nSo, now in our route's `loader` function, we can access the `networkStrength` hook from the router context:\n\n- `src/routes/posts.tsx`\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts')({\n component: Posts,\n loader: ({ context }) => {\n if (context.networkStrength === 'STRONG') {\n // Do something\n }\n },\n})\n```\n\n## Modifying the Router Context\n\nThe router context is passed down the route tree and is merged at each route. This means that you can modify the context at each route and the modifications will be available to all child routes. Here's an example:\n\n- `src/routes/__root.tsx`\n\n```tsx\nimport { createRootRouteWithContext } from '@tanstack/react-router'\n\ninterface MyRouterContext {\n foo: boolean\n}\n\nexport const Route = createRootRouteWithContext<MyRouterContext>()({\n component: App,\n})\n```\n\n- `src/router.tsx`\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nimport { routeTree } from './routeTree.gen'\n\nconst router = createRouter({\n routeTree,\n context: {\n foo: true,\n },\n})\n```\n\n- `src/routes/todos.tsx`\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/todos')({\n component: Todos,\n beforeLoad: () => {\n return {\n bar: true,\n }\n },\n loader: ({ context }) => {\n context.foo // true\n context.bar // true\n },\n})\n```\n\n## Processing Accumulated Route Context\n\nContext, especially the isolated route `context` objects, make it trivial to accumulate and process the route context objects for all matched routes. Here's an example where we use all of the matched route contexts to generate a breadcrumb trail:\n\n```tsx\n// src/routes/__root.tsx\nexport const Route = createRootRoute({\n component: () => {\n const matches = useRouterState({ select: (s) => s.matches })\n\n const breadcrumbs = matches\n .filter((match) => match.context.getTitle)\n .map(({ pathname, context }) => {\n return {\n title: context.getTitle(),\n path: pathname,\n }\n })\n\n // ...\n },\n})\n```\n\nUsing that same route context, we could also generate a title tag for our page's `<head>`:\n\n```tsx\n// src/routes/__root.tsx\nexport const Route = createRootRoute({\n component: () => {\n const matches = useRouterState({ select: (s) => s.matches })\n\n const matchWithTitle = [...matches]\n .reverse()\n .find((d) => d.context.getTitle)\n\n const title = matchWithTitle?.context.getTitle() || 'My App'\n\n return (\n <html>\n <head>\n <title>{title}</title>\n </head>\n <body>{/* ... */}</body>\n </html>\n )\n },\n})\n```\n\n# Scroll Restoration\n\n## Hash/Top-of-Page Scrolling\n\nOut of the box, TanStack Router supports both **hash scrolling** and **top-of-page scrolling** without any additional configuration.\n\n## Scroll-to-top & Nested Scrollable Areas\n\nBy default, scroll-to-top mimics the behavior of the browser, which means only the `window` itself is scrolled to the top after successful navigation. For many apps however, it's common for the main scrollable area to be a nested div or similar because of advanced layouts. If you would like TanStack Router to also scroll these main scrollable areas for you, you can add selectors to target them using the `routerOptions.scrollToTopSelectors`:\n\n```tsx\nconst router = createRouter({\n scrollToTopSelectors: ['#main-scrollable-area'],\n})\n```\n\nFor complex selectors that cannot be simply resolved using `document.querySelector(selector)`, you can pass functions that return HTML elements to `routerOptions.scrollToTopSelectors`:\n\n```tsx\nconst selector = () =>\n document\n .querySelector('#shadowRootParent')\n ?.shadowRoot?.querySelector('#main-scrollable-area')\n\nconst router = createRouter({\n scrollToTopSelectors: [selector],\n})\n```\n\nThese selectors are handled **in addition to `window`** which cannot be disabled currently.\n\n## Scroll Restoration\n\nScroll restoration is the process of restoring the scroll position of a page when the user navigates back to it. This is normally a built-in feature for standard HTML based websites, but can be difficult to replicate for SPA applications because:\n\n- SPAs typically use the `history.pushState` API for navigation, so the browser doesn't know to restore the scroll position natively\n- SPAs sometimes render content asynchronously, so the browser doesn't know the height of the page until after it's rendered\n- SPAs can sometimes use nested scrollable containers to force specific layouts and features.\n\nNot only that, but it's very common for applications to have multiple scrollable areas within an app, not just the body. For example, a chat application might have a scrollable sidebar and a scrollable chat area. In this case, you would want to restore the scroll position of both areas independently.\n\nTo alleviate this problem, TanStack Router provides a scroll restoration component and hook that handle the process of monitoring, caching and restoring scroll positions for you.\n\nIt does this by:\n\n- Monitoring the DOM for scroll events\n- Registering scrollable areas with the scroll restoration cache\n- Listening to the proper router events to know when to cache and restore scroll positions\n- Storing scroll positions for each scrollable area in the cache (including `window` and `body`)\n- Restoring scroll positions after successful navigations before DOM paint\n\nThat may sound like a lot, but for you, it's as simple as this:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n scrollRestoration: true,\n})\n```\n\n> [!NOTE]\n> The `<ScrollRestoration />` component still works, but has been deprecated.\n\n## Custom Cache Keys\n\nFalling in behind Remix's own Scroll Restoration APIs, you can also customize the key used to cache scroll positions for a given scrollable area using the `getKey` option. This could be used, for example, to force the same scroll position to be used regardless of the users browser history.\n\nThe `getKey` option receives the relevant `Location` state from TanStack Router and expects you to return a string to uniquely identify the scrollable measurements for that state.\n\nThe default `getKey` is `(location) => location.state.__TSR_key!`, where `__TSR_key` is the unique key generated for each entry in the history.\n\n> Older versions, prior to `v1.121.34`, used `state.key` as the default key, but this has been deprecated in favor of `state.__TSR_key`. For now, `location.state.key` will still be available for compatibility, but it will be removed in the next major version.\n\n## Examples\n\nYou could sync scrolling to the pathname:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n getScrollRestorationKey: (location) => location.pathname,\n})\n```\n\nYou can conditionally sync only some paths, then use the key for the rest:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n getScrollRestorationKey: (location) => {\n const paths = ['/', '/chat']\n return paths.includes(location.pathname)\n ? location.pathname\n : location.state.__TSR_key!\n },\n})\n```\n\n## Preventing Scroll Restoration\n\nSometimes you may want to prevent scroll restoration from happening. To do this you can utilize the `resetScroll` option available on the following APIs:\n\n- `<Link resetScroll={false}>`\n- `navigate({ resetScroll: false })`\n- `redirect({ resetScroll: false })`\n\nWhen `resetScroll` is set to `false`, the scroll position for the next navigation will not be restored (if navigating to an existing history event in the stack) or reset to the top (if it's a new history event in the stack).\n\n## Manual Scroll Restoration\n\nMost of the time, you won't need to do anything special to get scroll restoration to work. However, there are some cases where you may need to manually control scroll restoration. The most common example is **virtualized lists**.\n\nTo manually control scroll restoration for virtualized lists within the whole browser window:\n\n[//]: # 'VirtualizedWindowScrollRestorationExample'\n\n```tsx\nfunction Component() {\n const scrollEntry = useElementScrollRestoration({\n getElement: () => window,\n })\n\n // Let's use TanStack Virtual to virtualize some content!\n const virtualizer = useWindowVirtualizer({\n count: 10000,\n estimateSize: () => 100,\n // We pass the scrollY from the scroll restoration entry to the virtualizer\n // as the initial offset\n initialOffset: scrollEntry?.scrollY,\n })\n\n return (\n <div>\n {virtualizer.getVirtualItems().map(item => (\n ...\n ))}\n </div>\n )\n}\n```\n\n[//]: # 'VirtualizedWindowScrollRestorationExample'\n\nTo manually control scroll restoration for a specific element, you can use the `useElementScrollRestoration` hook and the `data-scroll-restoration-id` DOM attribute:\n\n[//]: # 'ManualRestorationExample'\n\n```tsx\nfunction Component() {\n // We need a unique ID for manual scroll restoration on a specific element\n // It should be as unique as possible for this element across your app\n const scrollRestorationId = 'myVirtualizedContent'\n\n // We use that ID to get the scroll entry for this element\n const scrollEntry = useElementScrollRestoration({\n id: scrollRestorationId,\n })\n\n // Let's use TanStack Virtual to virtualize some content!\n const virtualizerParentRef = React.useRef<HTMLDivElement>(null)\n const virtualizer = useVirtualizer({\n count: 10000,\n getScrollElement: () => virtualizerParentRef.current,\n estimateSize: () => 100,\n // We pass the scrollY from the scroll restoration entry to the virtualizer\n // as the initial offset\n initialOffset: scrollEntry?.scrollY,\n })\n\n return (\n <div\n ref={virtualizerParentRef}\n // We pass the scroll restoration ID to the element\n // as a custom attribute that will get picked up by the\n // scroll restoration watcher\n data-scroll-restoration-id={scrollRestorationId}\n className=\"flex-1 border rounded-lg overflow-auto relative\"\n >\n ...\n </div>\n )\n}\n```\n\n[//]: # 'ManualRestorationExample'\n\n## Scroll Behavior\n\nTo control the scroll behavior when navigating between pages, you can use the `scrollRestorationBehavior` option. This allows you to make the transition between pages instant instead of a smooth scroll. The global configuration of scroll restoration behavior has the same options as those supported by the browser, which are `smooth`, `instant`, and `auto` (see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#behavior) for more information).\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n scrollRestorationBehavior: 'instant',\n})\n```\n\n# Search Params\n\nSimilar to how TanStack Query made handling server-state in your React and Solid applications a breeze, TanStack Router aims to unlock the power of URL search params in your applications.\n\n> \uD83E\uDDE0 If you are on a really old browser, like IE11, you may need to use a polyfill for `URLSearchParams`.\n\n## Why not just use `URLSearchParams`?\n\nWe get it, you've been hearing a lot of \"use the platform\" lately and for the most part, we agree. However, we also believe it's important to recognize where the platform falls short for more advanced use-cases and we believe `URLSearchParams` is one of these circumstances.\n\nTraditional Search Param APIs usually assume a few things:\n\n- Search params are always strings\n- They are _mostly_ flat\n- Serializing and deserializing using `URLSearchParams` is good enough (Spoiler alert: it's not.)\n- Search params modifications are tightly coupled with the URL's pathname and must be updated together, even if the pathname is not changing.\n\nReality is very different from these assumptions though.\n\n- Search params represent application state, so inevitably, we will expect them to have the same DX associated with other state managers. This means having the capability of distinguishing between primitive value types and efficiently storing and manipulating complex data structures like nested arrays and objects.\n- There are many ways to serialize and deserialize state with different tradeoffs. You should be able to choose the best one for your application or at the very least get a better default than `URLSearchParams`.\n- Immutability & Structural Sharing. Every time you stringify and parse url search params, referential integrity and object identity is lost because each new parse creates a brand new data structure with a unique memory reference. If not properly managed over its lifetime, this constant serialization and parsing can result in unexpected and undesirable performance issues, especially in frameworks like React that choose to track reactivity via immutability or in Solid that normally relies on reconciliation to detect changes from deserialized data sources.\n- Search params, while an important part of the URL, do frequently change independently of the URL's pathname. For example, a user may want to change the page number of a paginated list without touching the URL's pathname.\n\n## Search Params, the \"OG\" State Manager\n\nYou've probably seen search params like `?page=3` or `?filter-name=tanner` in the URL. There is no question that this is truly **a form of global state** living inside of the URL. It's valuable to store specific pieces of state in the URL because:\n\n- Users should be able to:\n - Cmd/Ctrl + Click to open a link in a new tab and reliably see the state they expected\n - Bookmark and share links from your application with others with assurances that they will see exactly the state as when the link was copied.\n - Refresh your app or navigate back and forth between pages without losing their state\n- Developers should be able to easily:\n - Add, remove or modify state in the URL with the same great DX as other state managers\n - Easily validate search params coming from the URL in a format and type that is safe for their application to consume\n - Read and write to search params without having to worry about the underlying serialization format\n\n## JSON-first Search Params\n\nTo achieve the above, the first step built in to TanStack Router is a powerful search param parser that automatically converts the search string of your URL to structured JSON. This means that you can store any JSON-serializable data structure in your search params and it will be parsed and serialized as JSON. This is a huge improvement over `URLSearchParams` which has limited support for array-like structures and nested data.\n\nFor example, navigating to the following route:\n\n```tsx\nconst link = (\n <Link\n to=\"/shop\"\n search={{\n pageIndex: 3,\n includeCategories: ['electronics', 'gifts'],\n sortBy: 'price',\n desc: true,\n }}\n />\n)\n```\n\nWill result in the following URL:\n\n```\n/shop?pageIndex=3&includeCategories=%5B%22electronics%22%2C%22gifts%22%5D&sortBy=price&desc=true\n```\n\nWhen this URL is parsed, the search params will be accurately converted back to the following JSON:\n\n```json\n{\n \"pageIndex\": 3,\n \"includeCategories\": [\"electronics\", \"gifts\"],\n \"sortBy\": \"price\",\n \"desc\": true\n}\n```\n\nIf you noticed, there are a few things going on here:\n\n- The first level of the search params is flat and string based, just like `URLSearchParams`.\n- First level values that are not strings are accurately preserved as actual numbers and booleans.\n- Nested data structures are automatically converted to URL-safe JSON strings\n\n> \uD83E\uDDE0 It's common for other tools to assume that search params are always flat and string-based which is why we've chosen to keep things URLSearchParam compliant at the first level. This ultimately means that even though TanStack Router is managing your nested search params as JSON, other tools will still be able to write to the URL and read first-level params normally.\n\n## Validating and Typing Search Params\n\nDespite TanStack Router being able to parse search params into reliable JSON, they ultimately still came from **a user-facing raw-text input**. Similar to other serialization boundaries, this means that before you consume search params, they should be validated into a format that your application can trust and rely on.\n\n### Enter Validation + TypeScript!\n\nTanStack Router provides convenient APIs for validating and typing search params. This all starts with the `Route`'s `validateSearch` option:\n\n```tsx\n// /routes/shop.products.tsx\n\ntype ProductSearchSortOptions = 'newest' | 'oldest' | 'price'\n\ntype ProductSearch = {\n page: number\n filter: string\n sort: ProductSearchSortOptions\n}\n\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: (search: Record<string, unknown>): ProductSearch => {\n // validate and parse the search params into a typed state\n return {\n page: Number(search?.page ?? 1),\n filter: (search.filter as string) || '',\n sort: (search.sort as ProductSearchSortOptions) || 'newest',\n }\n },\n})\n```\n\nIn the above example, we're validating the search params of the `Route` and returning a typed `ProductSearch` object. This typed object is then made available to this route's other options **and any child routes, too!**\n\n### Validating Search Params\n\nThe `validateSearch` option is a function that is provided the JSON parsed (but non-validated) search params as a `Record<string, unknown>` and returns a typed object of your choice. It's usually best to provide sensible fallbacks for malformed or unexpected search params so your users' experience stays non-interrupted.\n\nHere's an example:\n\n```tsx\n// /routes/shop.products.tsx\n\ntype ProductSearchSortOptions = 'newest' | 'oldest' | 'price'\n\ntype ProductSearch = {\n page: number\n filter: string\n sort: ProductSearchSortOptions\n}\n\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: (search: Record<string, unknown>): ProductSearch => {\n // validate and parse the search params into a typed state\n return {\n page: Number(search?.page ?? 1),\n filter: (search.filter as string) || '',\n sort: (search.sort as ProductSearchSortOptions) || 'newest',\n }\n },\n})\n```\n\nHere's an example using the [Zod](https://zod.dev/) library (but feel free to use any validation library you want) to both validate and type the search params in a single step:\n\n```tsx\n// /routes/shop.products.tsx\n\nimport { z } from 'zod'\n\nconst productSearchSchema = z.object({\n page: z.number().catch(1),\n filter: z.string().catch(''),\n sort: z.enum(['newest', 'oldest', 'price']).catch('newest'),\n})\n\ntype ProductSearch = z.infer<typeof productSearchSchema>\n\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: (search) => productSearchSchema.parse(search),\n})\n```\n\nBecause `validateSearch` also accepts an object with the `parse` property, this can be shortened to:\n\n```tsx\nvalidateSearch: productSearchSchema\n```\n\nIn the above example, we used Zod's `.catch()` modifier instead of `.default()` to avoid showing an error to the user because we firmly believe that if a search parameter is malformed, you probably don't want to halt the user's experience through the app to show a big fat error message. That said, there may be times that you **do want to show an error message**. In that case, you can use `.default()` instead of `.catch()`.\n\nThe underlying mechanics why this works relies on the `validateSearch` function throwing an error. If an error is thrown, the route's `onError` option will be triggered (and `error.routerCode` will be set to `VALIDATE_SEARCH` and the `errorComponent` will be rendered instead of the route's `component` where you can handle the search param error however you'd like.\n\n#### Adapters\n\nWhen using a library like [Zod](https://zod.dev/) to validate search params you might want to `transform` search params before committing the search params to the URL. A common `zod` `transform` is `default` for example.\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { z } from 'zod'\n\nconst productSearchSchema = z.object({\n page: z.number().default(1),\n filter: z.string().default(''),\n sort: z.enum(['newest', 'oldest', 'price']).default('newest'),\n})\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: productSearchSchema,\n})\n```\n\nIt might be surprising that when you try to navigate to this route, `search` is required. The following `Link` will type error as `search` is missing.\n\n```tsx\n<Link to=\"/shop/products\" />\n```\n\nFor validation libraries we recommend using adapters which infer the correct `input` and `output` types.\n\n### Zod\n\nAn adapter is provided for [Zod](https://zod.dev/) which will pipe through the correct `input` type and `output` type\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { zodValidator } from '@tanstack/zod-adapter'\nimport { z } from 'zod'\n\nconst productSearchSchema = z.object({\n page: z.number().default(1),\n filter: z.string().default(''),\n sort: z.enum(['newest', 'oldest', 'price']).default('newest'),\n})\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: zodValidator(productSearchSchema),\n})\n```\n\nThe important part here is the following use of `Link` no longer requires `search` params\n\n```tsx\n<Link to=\"/shop/products\" />\n```\n\nHowever the use of `catch` here overrides the types and makes `page`, `filter` and `sort` `unknown` causing type loss. We have handled this case by providing a `fallback` generic function which retains the types but provides a `fallback` value when validation fails\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { fallback, zodValidator } from '@tanstack/zod-adapter'\nimport { z } from 'zod'\n\nconst productSearchSchema = z.object({\n page: fallback(z.number(), 1).default(1),\n filter: fallback(z.string(), '').default(''),\n sort: fallback(z.enum(['newest', 'oldest', 'price']), 'newest').default(\n 'newest',\n ),\n})\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: zodValidator(productSearchSchema),\n})\n```\n\nTherefore when navigating to this route, `search` is optional and retains the correct types.\n\nWhile not recommended, it is also possible to configure `input` and `output` type in case the `output` type is more accurate than the `input` type\n\n```tsx\nconst productSearchSchema = z.object({\n page: fallback(z.number(), 1).default(1),\n filter: fallback(z.string(), '').default(''),\n sort: fallback(z.enum(['newest', 'oldest', 'price']), 'newest').default(\n 'newest',\n ),\n})\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: zodValidator({\n schema: productSearchSchema,\n input: 'output',\n output: 'input',\n }),\n})\n```\n\nThis provides flexibility in which type you want to infer for navigation and which types you want to infer for reading search params.\n\n### Valibot\n\n> [!WARNING]\n> Router expects the valibot 1.0 package to be installed.\n\nWhen using [Valibot](https://valibot.dev/) an adapter is not needed to ensure the correct `input` and `output` types are used for navigation and reading search params. This is because `valibot` implements [Standard Schema](https://github.com/standard-schema/standard-schema)\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport * as v from 'valibot'\n\nconst productSearchSchema = v.object({\n page: v.optional(v.fallback(v.number(), 1), 1),\n filter: v.optional(v.fallback(v.string(), ''), ''),\n sort: v.optional(\n v.fallback(v.picklist(['newest', 'oldest', 'price']), 'newest'),\n 'newest',\n ),\n})\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: productSearchSchema,\n})\n```\n\n### Arktype\n\n> [!WARNING]\n> Router expects the arktype 2.0-rc package to be installed.\n\nWhen using [ArkType](https://arktype.io/) an adapter is not needed to ensure the correct `input` and `output` types are used for navigation and reading search params. This is because [ArkType](https://arktype.io/) implements [Standard Schema](https://github.com/standard-schema/standard-schema)\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { type } from 'arktype'\n\nconst productSearchSchema = type({\n page: 'number = 1',\n filter: 'string = \"\"',\n sort: '\"newest\" | \"oldest\" | \"price\" = \"newest\"',\n})\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: productSearchSchema,\n})\n```\n\n### Effect/Schema\n\nWhen using [Effect/Schema](https://effect.website/docs/schema/introduction/) an adapter is not needed to ensure the correct `input` and `output` types are used for navigation and reading search params. This is because [Effect/Schema](https://effect.website/docs/schema/standard-schema/) implements [Standard Schema](https://github.com/standard-schema/standard-schema)\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { Schema as S } from 'effect'\n\nconst productSearchSchema = S.standardSchemaV1(\n S.Struct({\n page: S.NumberFromString.pipe(\n S.optional,\n S.withDefaults({\n constructor: () => 1,\n decoding: () => 1,\n }),\n ),\n filter: S.String.pipe(\n S.optional,\n S.withDefaults({\n constructor: () => '',\n decoding: () => '',\n }),\n ),\n sort: S.Literal('newest', 'oldest', 'price').pipe(\n S.optional,\n S.withDefaults({\n constructor: () => 'newest' as const,\n decoding: () => 'newest' as const,\n }),\n ),\n }),\n)\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: productSearchSchema,\n})\n```\n\n## Reading Search Params\n\nOnce your search params have been validated and typed, you're finally ready to start reading and writing to them. There are a few ways to do this in TanStack Router, so let's check them out.\n\n### Using Search Params in Loaders\n\nPlease read the [Search Params in Loaders](./data-loading.md#using-loaderdeps-to-access-search-params) section for more information about how to read search params in loaders with the `loaderDeps` option.\n\n### Search Params are inherited from Parent Routes\n\nThe search parameters and types of parents are merged as you go down the route tree, so child routes also have access to their parent's search params:\n\n- `shop.products.tsx`\n\n```tsx\nconst productSearchSchema = z.object({\n page: z.number().catch(1),\n filter: z.string().catch(''),\n sort: z.enum(['newest', 'oldest', 'price']).catch('newest'),\n})\n\ntype ProductSearch = z.infer<typeof productSearchSchema>\n\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: productSearchSchema,\n})\n```\n\n- `shop.products.$productId.tsx`\n\n```tsx\nexport const Route = createFileRoute('/shop/products/$productId')({\n beforeLoad: ({ search }) => {\n search\n // ^? ProductSearch \u2705\n },\n})\n```\n\n### Search Params in Components\n\nYou can access your route's validated search params in your route's `component` via the `useSearch` hook.\n\n```tsx\n// /routes/shop.products.tsx\n\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: productSearchSchema,\n})\n\nconst ProductList = () => {\n const { page, filter, sort } = Route.useSearch()\n\n return <div>...</div>\n}\n```\n\n> [!TIP]\n> If your component is code-split, you can use the [getRouteApi function](./code-splitting.md#manually-accessing-route-apis-in-other-files-with-the-getrouteapi-helper) to avoid having to import the `Route` configuration to get access to the typed `useSearch()` hook.\n\n### Search Params outside of Route Components\n\nYou can access your route's validated search params anywhere in your app using the `useSearch` hook. By passing the `from` id/path of your origin route, you'll get even better type safety:\n\n```tsx\n// /routes/shop.products.tsx\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: productSearchSchema,\n // ...\n})\n\n// Somewhere else...\n\n// /components/product-list-sidebar.tsx\nconst routeApi = getRouteApi('/shop/products')\n\nconst ProductList = () => {\n const routeSearch = routeApi.useSearch()\n\n // OR\n\n const { page, filter, sort } = useSearch({\n from: Route.fullPath,\n })\n\n return <div>...</div>\n}\n```\n\nOr, you can loosen up the type-safety and get an optional `search` object by passing `strict: false`:\n\n```tsx\nfunction ProductList() {\n const search = useSearch({\n strict: false,\n })\n // {\n // page: number | undefined\n // filter: string | undefined\n // sort: 'newest' | 'oldest' | 'price' | undefined\n // }\n\n return <div>...</div>\n}\n```\n\n## Writing Search Params\n\nNow that you've learned how to read your route's search params, you'll be happy to know that you've already seen the primary APIs to modify and update them. Let's remind ourselves a bit\n\n### `<Link search />`\n\nThe best way to update search params is to use the `search` prop on the `<Link />` component.\n\nIf the search for the current page shall be updated and the `from` prop is specified, the `to` prop can be omitted. \nHere's an example:\n\n```tsx\n// /routes/shop.products.tsx\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: productSearchSchema,\n})\n\nconst ProductList = () => {\n return (\n <div>\n <Link from={Route.fullPath} search={(prev) => ({ page: prev.page + 1 })}>\n Next Page\n </Link>\n </div>\n )\n}\n```\n\nIf you want to update the search params in a generic component that is rendered on multiple routes, specifying `from` can be challenging.\n\nIn this scenario you can set `to=\".\"` which will give you access to loosely typed search params. \nHere is an example that illustrates this:\n\n```tsx\n// `page` is a search param that is defined in the __root route and hence available on all routes.\nconst PageSelector = () => {\n return (\n <div>\n <Link to=\".\" search={(prev) => ({ ...prev, page: prev.page + 1 })}>\n Next Page\n </Link>\n </div>\n )\n}\n```\n\nIf the generic component is only rendered in a specific subtree of the route tree, you can specify that subtree using `from`. Here you can omit `to='.'` if you want.\n\n```tsx\n// `page` is a search param that is defined in the /posts route and hence available on all of its child routes.\nconst PageSelector = () => {\n return (\n <div>\n <Link\n from=\"/posts\"\n to=\".\"\n search={(prev) => ({ ...prev, page: prev.page + 1 })}\n >\n Next Page\n </Link>\n </div>\n )\n```\n\n### `useNavigate(), navigate({ search })`\n\nThe `navigate` function also accepts a `search` option that works the same way as the `search` prop on `<Link />`:\n\n```tsx\n// /routes/shop.products.tsx\nexport const Route = createFileRoute('/shop/products/$productId')({\n validateSearch: productSearchSchema,\n})\n\nconst ProductList = () => {\n const navigate = useNavigate({ from: Route.fullPath })\n\n return (\n <div>\n <button\n onClick={() => {\n navigate({\n search: (prev) => ({ page: prev.page + 1 }),\n })\n }}\n >\n Next Page\n </button>\n </div>\n )\n}\n```\n\n### `router.navigate({ search })`\n\nThe `router.navigate` function works exactly the same way as the `useNavigate`/`navigate` hook/function above.\n\n### `<Navigate search />`\n\nThe `<Navigate search />` component works exactly the same way as the `useNavigate`/`navigate` hook/function above, but accepts its options as props instead of a function argument.\n\n## Transforming search with search middlewares\n\nWhen link hrefs are built, by default the only thing that matters for the query string part is the `search` property of a `<Link>`.\n\nTanStack Router provides a way to manipulate search params before the href is generated via **search middlewares**.\nSearch middlewares are functions that transform the search parameters when generating new links for a route or its descendants.\nThey are also executed upon navigation after search validation to allow manipulation of the query string.\n\nThe following example shows how to make sure that for **every** link that is being built, the `rootValue` search param is added _if_ it is part of the current search params. If a link specifies `rootValue` inside `search`, then that value is used for building the link.\n\n```tsx\nimport { z } from 'zod'\nimport { createFileRoute } from '@tanstack/react-router'\nimport { zodValidator } from '@tanstack/zod-adapter'\n\nconst searchSchema = z.object({\n rootValue: z.string().optional(),\n})\n\nexport const Route = createRootRoute({\n validateSearch: zodValidator(searchSchema),\n search: {\n middlewares: [\n ({ search, next }) => {\n const result = next(search)\n return {\n rootValue: search.rootValue,\n ...result,\n }\n },\n ],\n },\n})\n```\n\nSince this specific use case is quite common, TanStack Router provides a generic implementation to retain search params via `retainSearchParams`:\n\n```tsx\nimport { z } from 'zod'\nimport { createFileRoute, retainSearchParams } from '@tanstack/react-router'\nimport { zodValidator } from '@tanstack/zod-adapter'\n\nconst searchSchema = z.object({\n rootValue: z.string().optional(),\n})\n\nexport const Route = createRootRoute({\n validateSearch: zodValidator(searchSchema),\n search: {\n middlewares: [retainSearchParams(['rootValue'])],\n },\n})\n```\n\nAnother common use case is to strip out search params from links if their default value is set. TanStack Router provides a generic implementation for this use case via `stripSearchParams`:\n\n```tsx\nimport { z } from 'zod'\nimport { createFileRoute, stripSearchParams } from '@tanstack/react-router'\nimport { zodValidator } from '@tanstack/zod-adapter'\n\nconst defaultValues = {\n one: 'abc',\n two: 'xyz',\n}\n\nconst searchSchema = z.object({\n one: z.string().default(defaultValues.one),\n two: z.string().default(defaultValues.two),\n})\n\nexport const Route = createFileRoute('/hello')({\n validateSearch: zodValidator(searchSchema),\n search: {\n // strip default values\n middlewares: [stripSearchParams(defaultValues)],\n },\n})\n```\n\nMultiple middlewares can be chained. The following example shows how to combine both `retainSearchParams` and `stripSearchParams`.\n\n```tsx\nimport {\n Link,\n createFileRoute,\n retainSearchParams,\n stripSearchParams,\n} from '@tanstack/react-router'\nimport { z } from 'zod'\nimport { zodValidator } from '@tanstack/zod-adapter'\n\nconst defaultValues = ['foo', 'bar']\n\nexport const Route = createFileRoute('/search')({\n validateSearch: zodValidator(\n z.object({\n retainMe: z.string().optional(),\n arrayWithDefaults: z.string().array().default(defaultValues),\n required: z.string(),\n }),\n ),\n search: {\n middlewares: [\n retainSearchParams(['retainMe']),\n stripSearchParams({ arrayWithDefaults: defaultValues }),\n ],\n },\n})\n```\n\n# SSR\n\n> [!WARNING]\n> While every effort has been made to separate these APIs from changes to Tanstack Start, there are underlying shared implementations internally. Therefore these can be subject to change and should be regarded as experimental until Start reaches stable status.\n\nServer Side Rendering (SSR) is the process of rendering a component on the server and sending the HTML markup to the client. The client then hydrates the markup into a fully interactive component.\n\nThere are usually two different flavors of SSR to be considered:\n\n- Non-streaming SSR\n - The entire page is rendered on the server and sent to the client in one single HTML request, including the serialized data the application needs to hydrate on the client.\n- Streaming SSR\n - The critical first paint of the page is rendered on the server and sent to the client in one single HTML request, including the serialized data the application needs to hydrate on the client\n - The rest of the page is then streamed to the client as it is rendered on the server.\n\nThis guide will explain how to implement both flavors of SSR with TanStack Router!\n\n## Non-Streaming SSR\n\nNon-Streaming server-side rendering is the classic process of rendering the markup for your entire application page on the server and sending the completed HTML markup (and data) to the client. The client then hydrates the markup into a fully interactive application again.\n\nTo implement non-streaming SSR with TanStack Router, you will need the following utilities:\n\n- `RouterClient` from `@tanstack/react-router`\n - e.g. `<RouterClient router={router} />`\n - Rendering this component in your client entry will render your application and also automatically implement the `Wrap` component option on `Router`\n- And, either:\n - `defaultRenderHandler` from `@tanstack/react-router`\n - This will render your application in your server entry and also automatically handle application-level hydration/dehydration and also automatically implement the RouterServer component.\n or:\n - `renderRouterToString` from `@tanstack/react-router`\n - This differs from defaultRenderHandler in that it allows you to manually specify the `Wrap` component option on `Router` together with any other providers you may need to wrap it with.\n - `RouterServer` from `@tanstack/react-router`\n - This implements the `Wrap` component option on `Router`\n\n### Automatic Server History\n\nOn the client, Router defaults to using an instance of `createBrowserHistory`, which is the preferred type of history to use on the client. On the server, however, you will want to use an instance of `createMemoryHistory` instead. This is because `createBrowserHistory` uses the `window` object, which does not exist on the server. This is handled automatically for you in the RouterServer component.\n\n### Automatic Loader Dehydration/Hydration\n\nResolved loader data fetched by routes is automatically dehydrated and rehydrated by TanStack Router so long as you complete the standard SSR steps outlined in this guide.\n\n\u26A0\uFE0F If you are using deferred data streaming, you will also need to ensure that you have implemented the [SSR Streaming & Stream Transform](#streaming-ssr) pattern near the end of this guide.\n\nFor more information on how to utilize data loading, see the [Data Loading](./data-loading.md) guide.\n\n### Router Creation\n\nSince your router will exist both on the server and the client, it's important that you create your router in a way that is consistent between both of these environments. The easiest way to do this is to expose a `createRouter` function in a shared file that can be imported and called by both your server and client entry files.\n\n```tsx\n// src/router.tsx\nimport { createRouter as createTanstackRouter } from '@tanstack/react-router'\nimport { routeTree } from './routeTree.gen'\n\nexport function createRouter() {\n return createTanstackRouter({ routeTree })\n}\n\ndeclare module '@tanstack/react-router' {\n interface Register {\n router: ReturnType<typeof createRouter>\n }\n}\n```\n\n### Rendering the Application on the Server\n\nNow that you have a router instance that has loaded all the critical data for the current URL, you can render your application on the server:\n\nusing `defaultRenderHandler`\n\n```tsx\n// src/entry-server.tsx\nimport {\n createRequestHandler,\n defaultRenderToString,\n} from '@tanstack/react-router/ssr/server'\nimport { createRouter } from './router'\n\nexport async function render({ request }: { request: Request }) {\n const handler = createRequestHandler({ request, createRouter })\n\n return await handler(defaultRenderHandler)\n}\n```\n\nusing `renderRouterToString`\n\n```tsx\n// src/entry-server.tsx\nimport {\n createRequestHandler,\n renderRouterToString,\n RouterServer,\n} from '@tanstack/react-router/ssr/server'\nimport { createRouter } from './router'\n\nexport function render({ request }: { request: Request }) {\n const handler = createRequestHandler({ request, createRouter })\n\n return handler(({ request, responseHeaders, router }) =>\n renderRouterToString({\n request,\n responseHeaders,\n router,\n children: <RouterServer router={router} />,\n }),\n )\n}\n```\n\nNOTE: The createRequestHandler method requires a web api standard Request object, while the handler method will return a web api standard Response promise.\n\nShould you be using a server framework like Express that uses its own Request and Response objects you would need to convert from the one to the other. Please have a look at the examples for how such an implementation might look like.\n\n## Rendering the Application on the Client\n\nOn the client, things are much simpler.\n\n- Create your router instance\n- Render your application using the `<RouterClient />` component\n\n[//]: # 'ClientEntryFileExample'\n\n```tsx\n// src/entry-client.tsx\nimport { hydrateRoot } from 'react-dom/client'\nimport { RouterClient } from '@tanstack/react-router/ssr/client'\nimport { createRouter } from './router'\n\nconst router = createRouter()\n\nhydrateRoot(document, <RouterClient router={router} />)\n```\n\n[//]: # 'ClientEntryFileExample'\n\nWith this setup, your application will be rendered on the server and then hydrated on the client!\n\n## Streaming SSR\n\nStreaming SSR is the most modern flavor of SSR and is the process of continuously and incrementally sending HTML markup to the client as it is rendered on the server. This is slightly different from traditional SSR in concept because beyond being able to dehydrate and rehydrate a critical first paint, markup and data with lower priority or slower response times can be streamed to the client after the initial render, but in the same request.\n\nThis pattern can be useful for pages that have slow or high-latency data fetching requirements. For example, if you have a page that needs to fetch data from a third-party API, you can stream the critical initial markup and data to the client and then stream the less-critical third-party data to the client as it is resolved.\n\n> [!NOTE]\n> This streaming pattern is all automatic as long as you are using either `defaultStreamHandler` or `renderRouterToStream`.\n\nusing `defaultStreamHandler`\n\n```tsx\n// src/entry-server.tsx\nimport {\n createRequestHandler,\n defaultStreamHandler,\n} from '@tanstack/react-router/ssr/server'\nimport { createRouter } from './router'\n\nexport async function render({ request }: { request: Request }) {\n const handler = createRequestHandler({ request, createRouter })\n\n return await handler(defaultStreamHandler)\n}\n```\n\nusing `renderRouterToStream`\n\n```tsx\n// src/entry-server.tsx\nimport {\n createRequestHandler,\n renderRouterToStream,\n RouterServer,\n} from '@tanstack/react-router/ssr/server'\nimport { createRouter } from './router'\n\nexport function render({ request }: { request: Request }) {\n const handler = createRequestHandler({ request, createRouter })\n\n return handler(({ request, responseHeaders, router }) =>\n renderRouterToStream({\n request,\n responseHeaders,\n router,\n children: <RouterServer router={router} />,\n }),\n )\n}\n```\n\n## Streaming Dehydration/Hydration\n\nStreaming dehydration/hydration is an advanced pattern that goes beyond markup and allows you to dehydrate and stream any supporting data from the server to the client and rehydrate it on arrival. This is useful for applications that may need to further use/manage the underlying data that was used to render the initial markup on the server.\n\n## Data Serialization\n\nWhen using SSR, data passed between the server and the client must be serialized before it is sent across network-boundaries. TanStack Router handles this serialization using a very lightweight serializer that supports common data types beyond JSON.stringify/JSON.parse.\n\nOut of the box, the following types are supported:\n\n- `undefined`\n- `Date`\n- `Error`\n- `FormData`\n\nIf you feel that there are other types that should be supported by default, please open an issue on the TanStack Router repository.\n\nIf you are using more complex data types like `Map`, `Set`, `BigInt`, etc, you may need to use a custom serializer to ensure that your type-definitions are accurate and your data is correctly serialized and deserialized. We are currently working on both a more robust serializer and a way to customize the serializer for your application. Open an issue if you are interested in helping out!\n\n# Static Route Data\n\nWhen creating routes, you can optionally specify a `staticData` property in the route's options. This object can literally contain anything you want as long as it's synchronously available when you create your route.\n\nIn addition to being able to access this data from the route itself, you can also access it from any match under the `match.staticData` property.\n\n## Example\n\n- `posts.tsx`\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts')({\n staticData: {\n customData: 'Hello!',\n },\n})\n```\n\nYou can then access this data anywhere you have access to your routes, including matches that can be mapped back to their routes.\n\n- `__root.tsx`\n\n```tsx\nimport { createRootRoute } from '@tanstack/react-router'\n\nexport const Route = createRootRoute({\n component: () => {\n const matches = useMatches()\n\n return (\n <div>\n {matches.map((match) => {\n return <div key={match.id}>{match.staticData.customData}</div>\n })}\n </div>\n )\n },\n})\n```\n\n## Enforcing Static Data\n\nIf you want to enforce that a route has static data, you can use declaration merging to add a type to the route's static option:\n\n```tsx\ndeclare module '@tanstack/react-router' {\n interface StaticDataRouteOption {\n customData: string\n }\n}\n```\n\nNow, if you try to create a route without the `customData` property, you'll get a type error:\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts')({\n staticData: {\n // Property 'customData' is missing in type '{ customData: number; }' but required in type 'StaticDataRouteOption'.ts(2741)\n },\n})\n```\n\n## Optional Static Data\n\nIf you want to make static data optional, simply add a `?` to the property:\n\n```tsx\ndeclare module '@tanstack/react-router' {\n interface StaticDataRouteOption {\n customData?: string\n }\n}\n```\n\nAs long as there are any required properties on the `StaticDataRouteOption`, you'll be required to pass in an object.\n\n# Type Safety\n\nTanStack Router is built to be as type-safe as possible within the limits of the TypeScript compiler and runtime. This means that it's not only written in TypeScript, but that it also **fully infers the types it's provided and tenaciously pipes them through the entire routing experience**.\n\nUltimately, this means that you write **less types as a developer** and have **more confidence in your code** as it evolves.\n\n## Route Definitions\n\n### File-based Routing\n\nRoutes are hierarchical, and so are their definitions. If you're using file-based routing, much of the type-safety is already taken care of for you.\n\n### Code-based Routing\n\nIf you're using the `Route` class directly, you'll need to be aware of how to ensure your routes are typed properly using the `Route`'s `getParentRoute` option. This is because child routes need to be aware of **all** of their parent routes types. Without this, those precious search params you parsed out of your _layout_ and _pathless layout_ routes, 3 levels up, would be lost to the JS void.\n\nSo, don't forget to pass the parent route to your child routes!\n\n```tsx\nconst parentRoute = createRoute({\n getParentRoute: () => parentRoute,\n})\n```\n\n## Exported Hooks, Components, and Utilities\n\nFor the types of your router to work with top-level exports like `Link`, `useNavigate`, `useParams`, etc. they must permeate the TypeScript module boundary and be registered right into the library. To do this, we use declaration merging on the exported `Register` interface.\n\n```ts\nconst router = createRouter({\n // ...\n})\n\ndeclare module '@tanstack/react-router' {\n interface Register {\n router: typeof router\n }\n}\n```\n\nBy registering your router with the module, you can now use the exported hooks, components, and utilities with your router's exact types.\n\n## Fixing the Component Context Problem\n\nComponent context is a wonderful tool in React and other frameworks for providing dependencies to components. However, if that context is changing types as it moves throughout your component hierarchy, it becomes impossible for TypeScript to know how to infer those changes. To get around this, context-based hooks and components require that you give them a hint on how and where they are being used.\n\n```tsx\nexport const Route = createFileRoute('/posts')({\n component: PostsComponent,\n})\n\nfunction PostsComponent() {\n // Each route has type-safe versions of most of the built-in hooks from TanStack Router\n const params = Route.useParams()\n const search = Route.useSearch()\n\n // Some hooks require context from the *entire* router, not just the current route. To achieve type-safety here,\n // we must pass the `from` param to tell the hook our relative position in the route hierarchy.\n const navigate = useNavigate({ from: Route.fullPath })\n // ... etc\n}\n```\n\nEvery hook and component that requires a context hint will have a `from` param where you can pass the ID or path of the route you are rendering within.\n\n> \uD83E\uDDE0 Quick tip: If your component is code-split, you can use the [getRouteApi function](./code-splitting.md#manually-accessing-route-apis-in-other-files-with-the-getrouteapi-helper) to avoid having to pass in the `Route.fullPath` to get access to the typed `useParams()` and `useSearch()` hooks.\n\n### What if I don't know the route? What if it's a shared component?\n\nThe `from` property is optional, which means if you don't pass it, you'll get the router's best guess on what types will be available. Usually, that means you'll get a union of all of the types of all of the routes in the router.\n\n### What if I pass the wrong `from` path?\n\nIt's technically possible to pass a `from` that satisfies TypeScript, but may not match the actual route you are rendering within at runtime. In this case, each hook and component that supports `from` will detect if your expectations don't match the actual route you are rendering within, and will throw a runtime error.\n\n### What if I don't know the route, or it's a shared component, and I can't pass `from`?\n\nIf you are rendering a component that is shared across multiple routes, or you are rendering a component that is not within a route, you can pass `strict: false` instead of a `from` option. This will not only silence the runtime error, but will also give you relaxed, but accurate types for the potential hook you are calling. A good example of this is calling `useSearch` from a shared component:\n\n```tsx\nfunction MyComponent() {\n const search = useSearch({ strict: false })\n}\n```\n\nIn this case, the `search` variable will be typed as a union of all possible search params from all routes in the router.\n\n## Router Context\n\nRouter context is so extremely useful as it's the ultimate hierarchical dependency injection. You can supply context to the router and to each and every route it renders. As you build up this context, TanStack Router will merge it down with the hierarchy of routes, so that each route has access to the context of all of its parents.\n\nThe `createRootRouteWithContext` factory creates a new router with the instantiated type, which then creates a requirement for you to fulfill the same type contract to your router, and will also ensure that your context is properly typed throughout the entire route tree.\n\n```tsx\nconst rootRoute = createRootRouteWithContext<{ whateverYouWant: true }>()({\n component: App,\n})\n\nconst routeTree = rootRoute.addChildren([\n // ... all child routes will have access to `whateverYouWant` in their context\n])\n\nconst router = createRouter({\n routeTree,\n context: {\n // This will be required to be passed now\n whateverYouWant: true,\n },\n})\n```\n\n## Performance Recommendations\n\nAs your application scales, TypeScript check times will naturally increase. There are a few things to keep in mind when your application scales to keep your TS check times down.\n\n### Only infer types you need\n\nA great pattern with client side data caches (TanStack Query, etc.) is to prefetch data. For example with TanStack Query you might have a route which calls `queryClient.ensureQueryData` in a `loader`.\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId/deep')({\n loader: ({ context: { queryClient }, params: { postId } }) =>\n queryClient.ensureQueryData(postQueryOptions(postId)),\n component: PostDeepComponent,\n})\n\nfunction PostDeepComponent() {\n const params = Route.useParams()\n const data = useSuspenseQuery(postQueryOptions(params.postId))\n\n return <></>\n}\n```\n\nThis may look fine and for small route trees and you may not notice any TS performance issues. However in this case TS has to infer the loader's return type, despite it never being used in your route. If the loader data is a complex type with many routes that prefetch in this manner, it can slow down editor performance. In this case, the change is quite simple and let typescript infer Promise<void>.\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId/deep')({\n loader: async ({ context: { queryClient }, params: { postId } }) => {\n await queryClient.ensureQueryData(postQueryOptions(postId))\n },\n component: PostDeepComponent,\n})\n\nfunction PostDeepComponent() {\n const params = Route.useParams()\n const data = useSuspenseQuery(postQueryOptions(params.postId))\n\n return <></>\n}\n```\n\nThis way the loader data is never inferred and it moves the inference out of the route tree to the first time you use `useSuspenseQuery`.\n\n### Narrow to relevant routes as much as you possibly can\n\nConsider the following usage of `Link`\n\n```tsx\n<Link to=\"..\" search={{ page: 0 }} />\n<Link to=\".\" search={{ page: 0 }} />\n```\n\n**These examples are bad for TS performance**. That's because `search` resolves to a union of all `search` params for all routes and TS has to check whatever you pass to the `search` prop against this potentially big union. As your application grows, this check time will increase linearly to number of routes and search params. We have done our best to optimize for this case (TypeScript will typically do this work once and cache it) but the initial check against this large union is expensive. This also applies to `params` and other API's such as `useSearch`, `useParams`, `useNavigate` etc.\n\nInstead you should try to narrow to relevant routes with `from` or `to`.\n\n```tsx\n<Link from={Route.fullPath} to=\"..\" search={{page: 0}} />\n<Link from=\"/posts\" to=\"..\" search={{page: 0}} />\n```\n\nRemember you can always pass a union to `to` or `from` to narrow the routes you're interested in.\n\n```tsx\nconst from: '/posts/$postId/deep' | '/posts/' = '/posts/'\n<Link from={from} to='..' />\n```\n\nYou can also pass branches to `from` to only resolve `search` or `params` to be from any descendants of that branch:\n\n```tsx\nconst from = '/posts'\n<Link from={from} to='..' />\n```\n\n`/posts` could be a branch with many descendants which share the same `search` or `params`\n\n### Consider using the object syntax of `addChildren`\n\nIt's typical of routes to have `params` `search`, `loaders` or `context` that can even reference external dependencies which are also heavy on TS inference. For such applications, using objects for creating the route tree can be more performant than tuples.\n\n`createChildren` also can accept an object. For large route trees with complex routes and external libraries, objects can be much faster for TS to type check as opposed to large tuples. The performance gains depend on your project, what external dependencies you have and how the types for those libraries are written\n\n```tsx\nconst routeTree = rootRoute.addChildren({\n postsRoute: postsRoute.addChildren({ postRoute, postsIndexRoute }),\n indexRoute,\n})\n```\n\nNote this syntax is more verbose but has better TS performance. With file based routing, the route tree is generated for you so a verbose route tree is not a concern\n\n### Avoid internal types without narrowing\n\nIt's common you might want to re-use types exposed. For example you might be tempted to use `LinkProps` like so\n\n```tsx\nconst props: LinkProps = {\n to: '/posts/',\n}\n\nreturn (\n <Link {...props}>\n)\n```\n\n**This is VERY bad for TS Performance**. The problem here is `LinkProps` has no type arguments and is therefore an extremely large type. It includes `search` which is a union of all `search` params, it contains `params` which is a union of all `params`. When merging this object with `Link` it will do a structural comparison of this huge type.\n\nInstead you can use `as const satisfies` to infer a precise type and not `LinkProps` directly to avoid the huge check\n\n```tsx\nconst props = {\n to: '/posts/',\n} as const satisfies LinkProps\n\nreturn (\n <Link {...props}>\n)\n```\n\nAs `props` is not of type `LinkProps` and therefore this check is cheaper because the type is much more precise. You can also improve type checking further by narrowing `LinkProps`\n\n```tsx\nconst props = {\n to: '/posts/',\n} as const satisfies LinkProps<RegisteredRouter, string '/posts/'>\n\nreturn (\n <Link {...props}>\n)\n```\n\nThis is even faster as we're checking against the narrowed `LinkProps` type.\n\nYou can also use this to narrow the type of `LinkProps` to a specific type to be used as a prop or parameter to a function\n\n```tsx\nexport const myLinkProps = [\n {\n to: '/posts',\n },\n {\n to: '/posts/$postId',\n params: { postId: 'postId' },\n },\n] as const satisfies ReadonlyArray<LinkProps>\n\nexport type MyLinkProps = (typeof myLinkProps)[number]\n\nconst MyComponent = (props: { linkProps: MyLinkProps }) => {\n return <Link {...props.linkProps} />\n}\n```\n\nThis is faster than using `LinkProps` directly in a component because `MyLinkProps` is a much more precise type\n\nAnother solution is not to use `LinkProps` and to provide inversion of control to render a `Link` component narrowed to a specific route. Render props are a good method of inverting control to the user of a component\n\n```tsx\nexport interface MyComponentProps {\n readonly renderLink: () => React.ReactNode\n}\n\nconst MyComponent = (props: MyComponentProps) => {\n return <div>{props.renderLink()}</div>\n}\n\nconst Page = () => {\n return <MyComponent renderLink={() => <Link to=\"/absolute\" />} />\n}\n```\n\nThis particular example is very fast as we've inverted control of where we're navigating to the user of the component. The `Link` is narrowed to the exact route\nwe want to navigate to\n\n# Type Utilities\n\nMost types exposed by TanStack Router are internal, subject to breaking changes and not always easy to use. That is why TanStack Router has a subset of exposed types focused on ease of use with the intension to be used externally. These types provide the same type safe experience from TanStack Router's runtime concepts on the type level, with flexibility of where to provide type checking\n\n## Type checking Link options with `ValidateLinkOptions`\n\n`ValidateLinkOptions` type checks object literal types to ensure they conform to `Link` options at inference sites. For example, you may have a generic `HeadingLink` component which accepts a `title` prop along with `linkOptions`, the idea being this component can be re-used for any navigation.\n\n```tsx\nexport interface HeaderLinkProps<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TOptions = unknown,\n> {\n title: string\n linkOptions: ValidateLinkOptions<TRouter, TOptions>\n}\n\nexport function HeadingLink<TRouter extends RegisteredRouter, TOptions>(\n props: HeaderLinkProps<TRouter, TOptions>,\n): React.ReactNode\nexport function HeadingLink(props: HeaderLinkProps): React.ReactNode {\n return (\n <>\n <h1>{props.title}</h1>\n <Link {...props.linkOptions} />\n </>\n )\n}\n```\n\nA more permissive overload of `HeadingLink` is used to avoid type assertions you would otherwise have to do with the generic signature. Using a looser signature without type parameters is an easy way to avoid type assertions in the implementation of `HeadingLink`\n\nAll type parameters for utilities are optional but for the best TypeScript performance `TRouter` should always be specified for the public facing signature. And `TOptions` should always be used at inference sites like `HeadingLink` to infer the `linkOptions` to correctly narrow `params` and `search`\n\nThe result of this is that `linkOptions` in the following is completely type-safe\n\n```tsx\n<HeadingLink title=\"Posts\" linkOptions={{ to: '/posts' }} />\n<HeadingLink title=\"Post\" linkOptions={{ to: '/posts/$postId', params: {postId: 'postId'} }} />\n```\n\n## Type checking an array of Link options with `ValidateLinkOptionsArray`\n\nAll navigation type utilities have an array variant. `ValidateLinkOptionsArray` enables type checking of an array of `Link` options. For example, you might have a generic `Menu` component where each item is a `Link`.\n\n```tsx\nexport interface MenuProps<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TItems extends ReadonlyArray<unknown> = ReadonlyArray<unknown>,\n> {\n items: ValidateLinkOptionsArray<TRouter, TItems>\n}\n\nexport function Menu<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TItems extends ReadonlyArray<unknown>,\n>(props: MenuProps<TRouter, TItems>): React.ReactNode\nexport function Menu(props: MenuProps): React.ReactNode {\n return (\n <ul>\n {props.items.map((item) => (\n <li>\n <Link {...item} />\n </li>\n ))}\n </ul>\n )\n}\n```\n\nThis of course allows the following `items` prop to be completely type-safe\n\n```tsx\n<Menu\n items={[\n { to: '/posts' },\n { to: '/posts/$postId', params: { postId: 'postId' } },\n ]}\n/>\n```\n\nIt is also possible to fix `from` for each `Link` options in the array. This would allow all `Menu` items to navigate relative to `from`. Additional type checking of `from` can be provided by the `ValidateFromPath` utility\n\n```tsx\nexport interface MenuProps<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TItems extends ReadonlyArray<unknown> = ReadonlyArray<unknown>,\n TFrom extends string = string,\n> {\n from: ValidateFromPath<TRouter, TFrom>\n items: ValidateLinkOptionsArray<TRouter, TItems, TFrom>\n}\n\nexport function Menu<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TItems extends ReadonlyArray<unknown>,\n TFrom extends string = string,\n>(props: MenuProps<TRouter, TItems, TFrom>): React.ReactNode\nexport function Menu(props: MenuProps): React.ReactNode {\n return (\n <ul>\n {props.items.map((item) => (\n <li>\n <Link {...item} from={props.from} />\n </li>\n ))}\n </ul>\n )\n}\n```\n\n`ValidateLinkOptionsArray` allows you to fix `from` by providing an extra type parameter. The result is a type safe array of `Link` options providing navigation relative to `from`\n\n```tsx\n<Menu\n from=\"/posts\"\n items={[{ to: '.' }, { to: './$postId', params: { postId: 'postId' } }]}\n/>\n```\n\n## Type checking redirect options with `ValidateRedirectOptions`\n\n`ValidateRedirectOptions` type checks object literal types to ensure they conform to redirect options at inference sites. For example, you may need a generic `fetchOrRedirect` function which accepts a `url` along with `redirectOptions`, the idea being this function will redirect when the `fetch` fails.\n\n```tsx\nexport async function fetchOrRedirect<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TOptions,\n>(\n url: string,\n redirectOptions: ValidateRedirectOptions<TRouter, TOptions>,\n): Promise<unknown>\nexport async function fetchOrRedirect(\n url: string,\n redirectOptions: ValidateRedirectOptions,\n): Promise<unknown> {\n const response = await fetch(url)\n\n if (!response.ok && response.status === 401) {\n throw redirect(redirectOptions)\n }\n\n return await response.json()\n}\n```\n\nThe result is that `redirectOptions` passed to `fetchOrRedirect` is completely type-safe\n\n```tsx\nfetchOrRedirect('http://example.com/', { to: '/login' })\n```\n\n## Type checking navigate options with `ValidateNavigateOptions`\n\n`ValidateNavigateOptions` type checks object literal types to ensure they conform to navigate options at inference sites. For example, you may want to write a custom hook to enable/disable navigation.\n\n[//]: # 'TypeCheckingNavigateOptionsWithValidateNavigateOptionsImpl'\n\n```tsx\nexport interface UseConditionalNavigateResult {\n enable: () => void\n disable: () => void\n navigate: () => void\n}\n\nexport function useConditionalNavigate<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TOptions,\n>(\n navigateOptions: ValidateNavigateOptions<TRouter, TOptions>,\n): UseConditionalNavigateResult\nexport function useConditionalNavigate(\n navigateOptions: ValidateNavigateOptions,\n): UseConditionalNavigateResult {\n const [enabled, setEnabled] = useState(false)\n const navigate = useNavigate()\n return {\n enable: () => setEnabled(true),\n disable: () => setEnabled(false),\n navigate: () => {\n if (enabled) {\n navigate(navigateOptions)\n }\n },\n }\n}\n```\n\n[//]: # 'TypeCheckingNavigateOptionsWithValidateNavigateOptionsImpl'\n\nThe result of this is that `navigateOptions` passed to `useConditionalNavigate` is completely type-safe and we can enable/disable navigation based on react state\n\n```tsx\nconst { enable, disable, navigate } = useConditionalNavigate({\n to: '/posts/$postId',\n params: { postId: 'postId' },\n})\n```\n\n";
1
+ declare const _default: "# Authenticated Routes\n\nAuthentication is an extremely common requirement for web applications. In this guide, we'll walk through how to use TanStack Router to build protected routes, and how to redirect users to login if they try to access them.\n\n## The `route.beforeLoad` Option\n\nThe `route.beforeLoad` option allows you to specify a function that will be called before a route is loaded. It receives all of the same arguments that the `route.loader` function does. This is a great place to check if a user is authenticated, and redirect them to a login page if they are not.\n\nThe `beforeLoad` function runs in relative order to these other route loading functions:\n\n- Route Matching (Top-Down)\n - `route.params.parse`\n - `route.validateSearch`\n- Route Loading (including Preloading)\n - **`route.beforeLoad`**\n - `route.onError`\n- Route Loading (Parallel)\n - `route.component.preload?`\n - `route.load`\n\n**It's important to know that the `beforeLoad` function for a route is called _before any of its child routes' `beforeLoad` functions_.** It is essentially a middleware function for the route and all of its children.\n\n**If you throw an error in `beforeLoad`, none of its children will attempt to load**.\n\n## Redirecting\n\nWhile not required, some authentication flows require redirecting to a login page. To do this, you can **throw a `redirect()`** from `beforeLoad`:\n\n```tsx\n// src/routes/_authenticated.tsx\nexport const Route = createFileRoute('/_authenticated')({\n beforeLoad: async ({ location }) => {\n if (!isAuthenticated()) {\n throw redirect({\n to: '/login',\n search: {\n // Use the current location to power a redirect after login\n // (Do not use `router.state.resolvedLocation` as it can\n // potentially lag behind the actual current location)\n redirect: location.href,\n },\n })\n }\n },\n})\n```\n\n> [!TIP]\n> The `redirect()` function takes all of the same options as the `navigate` function, so you can pass options like `replace: true` if you want to replace the current history entry instead of adding a new one.\n\nOnce you have authenticated a user, it's also common practice to redirect them back to the page they were trying to access. To do this, you can utilize the `redirect` search param that we added in our original redirect. Since we'll be replacing the entire URL with what it was, `router.history.push` is better suited for this than `router.navigate`:\n\n```tsx\nrouter.history.push(search.redirect)\n```\n\n## Non-Redirected Authentication\n\nSome applications choose to not redirect users to a login page, and instead keep the user on the same page and show a login form that either replaces the main content or hides it via a modal. This is also possible with TanStack Router by simply short circuiting rendering the `<Outlet />` that would normally render the child routes:\n\n```tsx\n// src/routes/_authenticated.tsx\nexport const Route = createFileRoute('/_authenticated')({\n component: () => {\n if (!isAuthenticated()) {\n return <Login />\n }\n\n return <Outlet />\n },\n})\n```\n\nThis keeps the user on the same page, but still allows you to render a login form. Once the user is authenticated, you can simply render the `<Outlet />` and the child routes will be rendered.\n\n## Authentication using React context/hooks\n\nIf your authentication flow relies on interactions with React context and/or hooks, you'll need to pass down your authentication state to TanStack Router using `router.context` option.\n\n> [!IMPORTANT]\n> React hooks are not meant to be consumed outside of React components. If you need to use a hook outside of a React component, you need to extract the returned state from the hook in a component that wraps your `<RouterProvider />` and then pass the returned value down to TanStack Router.\n\nWe'll cover the `router.context` options in-detail in the [Router Context](./router-context.md) section.\n\nHere's an example that uses React context and hooks for protecting authenticated routes in TanStack Router. See the entire working setup in the [Authenticated Routes example](https://github.com/TanStack/router/tree/main/examples/react/authenticated-routes).\n\n- `src/routes/__root.tsx`\n\n```tsx\nimport { createRootRouteWithContext } from '@tanstack/react-router'\n\ninterface MyRouterContext {\n // The ReturnType of your useAuth hook or the value of your AuthContext\n auth: AuthState\n}\n\nexport const Route = createRootRouteWithContext<MyRouterContext>()({\n component: () => <Outlet />,\n})\n```\n\n- `src/router.tsx`\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nimport { routeTree } from './routeTree.gen'\n\nexport const router = createRouter({\n routeTree,\n context: {\n // auth will initially be undefined\n // We'll be passing down the auth state from within a React component\n auth: undefined!,\n },\n})\n```\n\n- `src/App.tsx`\n\n```tsx\nimport { RouterProvider } from '@tanstack/react-router'\n\nimport { AuthProvider, useAuth } from './auth'\n\nimport { router } from './router'\n\nfunction InnerApp() {\n const auth = useAuth()\n return <RouterProvider router={router} context={{ auth }} />\n}\n\nfunction App() {\n return (\n <AuthProvider>\n <InnerApp />\n </AuthProvider>\n )\n}\n```\n\nThen in the authenticated route, you can check the auth state using the `beforeLoad` function, and **throw a `redirect()`** to your **Login route** if the user is not signed-in.\n\n- `src/routes/dashboard.route.tsx`\n\n```tsx\nimport { createFileRoute, redirect } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/dashboard')({\n beforeLoad: ({ context, location }) => {\n if (!context.auth.isAuthenticated) {\n throw redirect({\n to: '/login',\n search: {\n redirect: location.href,\n },\n })\n }\n },\n})\n```\n\nYou can _optionally_, also use the [Non-Redirected Authentication](#non-redirected-authentication) approach to show a login form instead of calling a **redirect**.\n\nThis approach can also be used in conjunction with Pathless or Layout Route to protect all routes under their parent route.\n\n## Related How-To Guides\n\nFor detailed, step-by-step implementation guides, see:\n\n- [How to Set Up Basic Authentication](../how-to/setup-authentication.md) - Complete setup with React Context and protected routes\n- [How to Integrate Authentication Providers](../how-to/setup-auth-providers.md) - Use Auth0, Clerk, or Supabase\n- [How to Set Up Role-Based Access Control](../how-to/setup-rbac.md) - Implement permissions and role-based routing\n\n## Examples\n\nWorking authentication examples are available in the repository:\n\n- [Basic Authentication Example](https://github.com/TanStack/router/tree/main/examples/react/authenticated-routes) - Simple authentication with context\n- [Firebase Authentication](https://github.com/TanStack/router/tree/main/examples/react/authenticated-routes-firebase) - Firebase Auth integration\n- [TanStack Start Auth Examples](https://github.com/TanStack/router/tree/main/examples/react) - Various auth implementations with TanStack Start\n\n# Automatic Code Splitting\n\nThe automatic code splitting feature in TanStack Router allows you to optimize your application's bundle size by lazily loading route components and their associated data. This is particularly useful for large applications where you want to minimize the initial load time by only loading the necessary code for the current route.\n\nTo turn this feature on, simply set the `autoCodeSplitting` option to `true` in your bundler plugin configuration. This enables the router to automatically handle code splitting for your routes without requiring any additional setup.\n\n```ts\n// vite.config.ts\nimport { defineConfig } from 'vite'\nimport { tanstackRouter } from '@tanstack/router-plugin/vite'\n\nexport default defineConfig({\n plugins: [\n tanstackRouter({\n autoCodeSplitting: true, // Enable automatic code splitting\n }),\n ],\n})\n```\n\nBut that's just the beginning! TanStack Router's automatic code splitting is not only easy to enable, but it also provides powerful customization options to tailor how your routes are split into chunks. This allows you to optimize your application's performance based on your specific needs and usage patterns.\n\n## How does it work?\n\nTanStack Router's automatic code splitting works by transforming your route files both during 'development' and at 'build' time. It rewrites the route definitions to use lazy-loading wrappers for components and loaders, which allows the bundler to group these properties into separate chunks.\n\n> [!TIP]\n> A **chunk** is a file that contains a portion of your application's code, which can be loaded on demand. This helps reduce the initial load time of your application by only loading the code that is needed for the current route.\n\nSo when your application loads, it doesn't include all the code for every route. Instead, it only includes the code for the routes that are initially needed. As users navigate through your application, additional chunks are loaded on demand.\n\nThis happens seamlessly, without requiring you to manually split your code or manage lazy loading. The TanStack Router bundler plugin takes care of everything, ensuring that your routes are optimized for performance right out of the box.\n\n### The transformation process\n\nWhen you enable automatic code splitting, the bundler plugin does this by using static code analysis look at your the code in your route files to transform them into optimized outputs.\n\nThis transformation process produces two key outputs when each of your route files are processed:\n\n1. **Reference File**: The bundler plugin takes your original route file (e.g., `posts.route.tsx`) and modifies the values for properties like `component` or `pendingComponent` to use special lazy-loading wrappers that'll fetch the actual code later. These wrappers point to a \"virtual\" file that the bundler will resolve later on.\n2. **Virtual File**: When the bundler sees a request for one of these virtual files (e.g., `posts.route.tsx?tsr-split=component`), it intercepts it to generate a new, minimal on-the-fly file that _only_ contains the code for the requested properties (e.g., just the `PostsComponent`).\n\nThis process ensures that your original code remains clean and readable, while the actual bundled output is optimized for initial bundle size.\n\n### What gets code split?\n\nThe decision of what to split into separate chunks is crucial for optimizing your application's performance. TanStack Router uses a concept called \"**Split Groupings**\" to determine how different parts of your route should be bundled together.\n\nSplit groupings are arrays of properties that tell TanStack Router how to bundle different parts of your route together. Each grouping is an list of property names that you want to bundle together into a single lazy-loaded chunk.\n\nThe available properties to split are:\n\n- `component`\n- `errorComponent`\n- `pendingComponent`\n- `notFoundComponent`\n- `loader`\n\nBy default, TanStack Router uses the following split groupings:\n\n```sh\n[\n ['component'],\n ['errorComponent'],\n ['notFoundComponent']\n]\n```\n\nThis means that it creates three separate lazy-loaded chunks for each route. Resulting in:\n\n- One for the main component\n- One for the error component\n- And one for the not-found component.\n\n### Rules of Splitting\n\nFor automatic code splitting to work, there are some rules in-place to make sure that this process can reliably and predictably happen.\n\n#### Do not export route properties\n\nRoute properties like `component`, `loader`, etc., should not be exported from the route file. Exporting these properties results in them being bundled into the main application bundle, which means that they will not be code-split.\n\n```tsx\nimport { createRoute } from '@tanstack/react-router'\n\nexport const Route = createRoute('/posts')({\n // ...\n notFoundComponent: PostsNotFoundComponent,\n})\n\n// \u274C Do NOT do this!\n// Exporting the notFoundComponent will prevent it from being code-split\n// and will be included in the main bundle.\nexport function PostsNotFoundComponent() {\n // \u274C\n // ...\n}\n\nfunction PostsNotFoundComponent() {\n // \u2705\n // ...\n}\n```\n\n**That's it!** There are no other restrictions. You can use any other JavaScript or TypeScript features in your route files as you normally would. If you run into any issues, please [open an issue](https://github.com/tanstack/router/issues) on GitHub.\n\n## Granular control\n\nFor most applications, the default behavior of using `autoCodeSplitting: true` is sufficient. However, TanStack Router provides several options to customize how your routes are split into chunks, allowing you to optimize for specific use cases or performance needs.\n\n### Global code splitting behavior (`defaultBehavior`)\n\nYou can change how TanStack Router splits your routes by changing the `defaultBehavior` option in your bundler plugin configuration. This allows you to define how different properties of your routes should be bundled together.\n\nFor example, to bundle all UI-related components into a single chunk, you could configure it like this:\n\n```ts\n// vite.config.ts\nimport { defineConfig } from 'vite'\nimport { tanstackRouter } from '@tanstack/router-plugin/vite'\n\nexport default defineConfig({\n plugins: [\n tanstackRouter({\n autoCodeSplitting: true,\n codeSplittingOptions: {\n defaultBehavior: [\n [\n 'component',\n 'pendingComponent',\n 'errorComponent',\n 'notFoundComponent',\n ], // Bundle all UI components together\n ],\n },\n }),\n ],\n})\n```\n\n### Advanced programmatic control (`splitBehavior`)\n\nFor complex rulesets, you can use the `splitBehavior` function in your vite config to programmatically define how routes should be split into chunks based on their `routeId`. This function allows you to implement custom logic for grouping properties together, giving you fine-grained control over the code splitting behavior.\n\n```ts\n// vite.config.ts\nimport { defineConfig } from 'vite'\nimport { tanstackRouter } from '@tanstack/router-plugin/vite'\n\nexport default defineConfig({\n plugins: [\n tanstackRouter({\n autoCodeSplitting: true,\n codeSplittingOptions: {\n splitBehavior: ({ routeId }) => {\n // For all routes under /posts, bundle the loader and component together\n if (routeId.startsWith('/posts')) {\n return [['loader', 'component']]\n }\n // All other routes will use the `defaultBehavior`\n },\n },\n }),\n ],\n})\n```\n\n### Per-route overrides (`codeSplitGroupings`)\n\nFor ultimate control, you can override the global configuration directly inside a route file by adding a `codeSplitGroupings` property. This is useful for routes that have unique optimization needs.\n\n```tsx\n// src/routes/posts.route.tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { loadPostsData } from './-heavy-posts-utils'\n\nexport const Route = createFileRoute('/posts')({\n // For this specific route, bundle the loader and component together.\n codeSplitGroupings: [['loader', 'component']],\n loader: () => loadPostsData(),\n component: PostsComponent,\n})\n\nfunction PostsComponent() {\n // ...\n}\n```\n\nThis will create a single chunk that includes both the `loader` and the `component` for this specific route, overriding both the default behavior and any programmatic split behavior defined in your bundler config.\n\n### Configuration order matters\n\nThis guide has so far describe three different ways to configure how TanStack Router splits your routes into chunks.\n\nTo make sure that the different configurations do not conflict with each other, TanStack Router uses the following order of precedence:\n\n1. **Per-route overrides**: The `codeSplitGroupings` property inside a route file takes the highest precedence. This allows you to define specific split groupings for individual routes.\n2. **Programmatic split behavior**: The `splitBehavior` function in your bundler config allows you to define custom logic for how routes should be split based on their `routeId`.\n3. **Default behavior**: The `defaultBehavior` option in your bundler config serves as the fallback for any routes that do not have specific overrides or custom logic defined. This is the base configuration that applies to all routes unless overridden.\n\n### Splitting the Data Loader\n\nThe `loader` function is responsible for fetching data needed by the route. By default, it is bundled with into your \"reference file\" and loaded in the initial bundle. However, you can also split the `loader` into its own chunk if you want to optimize further.\n\n> [!CAUTION]\n> Moving the `loader` into its own chunk is a **performance trade-off**. It introduces an additional trip to the server before the data can be fetched, which can lead to slower initial page loads. This is because the `loader` **must** be fetched and executed before the route can render its component.\n> Therefore, we recommend keeping the `loader` in the initial bundle unless you have a specific reason to split it.\n\n```ts\n// vite.config.ts\nimport { defineConfig } from 'vite'\nimport { tanstackRouter } from '@tanstack/router-plugin/vite'\n\nexport default defineConfig({\n plugins: [\n tanstackRouter({\n autoCodeSplitting: true,\n codeSplittingOptions: {\n defaultBehavior: [\n ['loader'], // The loader will be in its own chunk\n ['component'],\n // ... other component groupings\n ],\n },\n }),\n ],\n})\n```\n\nWe highly discourage splitting the `loader` unless you have a specific use case that requires it. In most cases, not splitting off the `loader` and keep it in the main bundle is the best choice for performance.\n\n# Code Splitting\n\nCode splitting and lazy loading is a powerful technique for improving the bundle size and load performance of an application.\n\n- Reduces the amount of code that needs to be loaded on initial page load\n- Code is loaded on-demand when it is needed\n- Results in more chunks that are smaller in size that can be cached more easily by the browser.\n\n## How does TanStack Router split code?\n\nTanStack Router separates code into two categories:\n\n- **Critical Route Configuration** - The code that is required to render the current route and kick off the data loading process as early as possible.\n - Path Parsing/Serialization\n - Search Param Validation\n - Loaders, Before Load\n - Route Context\n - Static Data\n - Links\n - Scripts\n - Styles\n - All other route configuration not listed below\n\n- **Non-Critical/Lazy Route Configuration** - The code that is not required to match the route, and can be loaded on-demand.\n - Route Component\n - Error Component\n - Pending Component\n - Not-found Component\n\n> \uD83E\uDDE0 **Why is the loader not split?**\n>\n> - The loader is already an asynchronous boundary, so you pay double to both get the chunk _and_ wait for the loader to execute.\n> - Categorically, it is less likely to contribute to a large bundle size than a component.\n> - The loader is one of the most important preloadable assets for a route, especially if you're using a default preload intent, like hovering over a link, so it's important for the loader to be available without any additional async overhead.\n>\n> Knowing the disadvantages of splitting the loader, if you still want to go ahead with it, head over to the [Data Loader Splitting](#data-loader-splitting) section.\n\n## Encapsulating a route's files into a directory\n\nSince TanStack Router's file-based routing system is designed to support both flat and nested file structures, it's possible to encapsulate a route's files into a single directory without any additional configuration.\n\nTo encapsulate a route's files into a directory, move the route file itself into a `.route` file within a directory with the same name as the route file.\n\nFor example, if you have a route file named `posts.tsx`, you would create a new directory named `posts` and move the `posts.tsx` file into that directory, renaming it to `route.tsx`.\n\n**Before**\n\n- `posts.tsx`\n\n**After**\n\n- `posts`\n - `route.tsx`\n\n## Approaches to code splitting\n\nTanStack Router supports multiple approaches to code splitting. If you are using code-based routing, skip to the [Code-Based Splitting](#code-based-splitting) section.\n\nWhen you are using file-based routing, you can use the following approaches to code splitting:\n\n- [Using automatic code-splitting \u2728](#using-automatic-code-splitting)\n- [Using the `.lazy.tsx` suffix](#using-the-lazytsx-suffix)\n- [Using Virtual Routes](#using-virtual-routes)\n\n## Using automatic code-splitting\u2728\n\nThis is the easiest and most powerful way to code split your route files.\n\nWhen using the `autoCodeSplitting` feature, TanStack Router will automatically code split your route files based on the non-critical route configuration mentioned above.\n\n> [!IMPORTANT]\n> The automatic code-splitting feature is **ONLY** available when you are using file-based routing with one of our [supported bundlers](../routing/file-based-routing.md#getting-started-with-file-based-routing).\n> This will **NOT** work if you are **only** using the CLI (`@tanstack/router-cli`).\n\nTo enable automatic code-splitting, you just need to add the following to the configuration of your TanStack Router Bundler Plugin:\n\n```ts\n// vite.config.ts\nimport { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\nimport { tanstackRouter } from '@tanstack/router-plugin/vite'\n\nexport default defineConfig({\n plugins: [\n tanstackRouter({\n // ...\n autoCodeSplitting: true,\n }),\n react(), // Make sure to add this plugin after the TanStack Router Bundler plugin\n ],\n})\n```\n\nThat's it! TanStack Router will automatically code-split all your route files by their critical and non-critical route configurations.\n\nIf you want more control over the code-splitting process, head over to the [Automatic Code Splitting](./automatic-code-splitting.md) guide to learn more about the options available.\n\n## Using the `.lazy.tsx` suffix\n\nIf you are not able to use the automatic code-splitting feature, you can still code-split your route files using the `.lazy.tsx` suffix. It is **as easy as moving your code into a separate file with a `.lazy.tsx` suffix** and using the `createLazyFileRoute` function instead of `createFileRoute`.\n\n> [!IMPORTANT]\n> The `__root.tsx` route file, using either `createRootRoute` or `createRootRouteWithContext`, does not support code splitting, since it's always rendered regardless of the current route.\n\nThese are the only options that `createLazyFileRoute` supports:\n\n| Export Name | Description |\n| ------------------- | --------------------------------------------------------------------- |\n| `component` | The component to render for the route. |\n| `errorComponent` | The component to render when an error occurs while loading the route. |\n| `pendingComponent` | The component to render while the route is loading. |\n| `notFoundComponent` | The component to render if a not-found error gets thrown. |\n\n### Example code splitting with `.lazy.tsx`\n\nWhen you are using `.lazy.tsx` you can split your route into two files to enable code splitting:\n\n**Before (Single File)**\n\n```tsx\n// src/routes/posts.tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { fetchPosts } from './api'\n\nexport const Route = createFileRoute('/posts')({\n loader: fetchPosts,\n component: Posts,\n})\n\nfunction Posts() {\n // ...\n}\n```\n\n**After (Split into two files)**\n\nThis file would contain the critical route configuration:\n\n```tsx\n// src/routes/posts.tsx\n\nimport { createFileRoute } from '@tanstack/react-router'\nimport { fetchPosts } from './api'\n\nexport const Route = createFileRoute('/posts')({\n loader: fetchPosts,\n})\n```\n\nWith the non-critical route configuration going into the file with the `.lazy.tsx` suffix:\n\n```tsx\n// src/routes/posts.lazy.tsx\nimport { createLazyFileRoute } from '@tanstack/react-router'\n\nexport const Route = createLazyFileRoute('/posts')({\n component: Posts,\n})\n\nfunction Posts() {\n // ...\n}\n```\n\n## Using Virtual Routes\n\nYou might run into a situation where you end up splitting out everything from a route file, leaving it empty! In this case, simply **delete the route file entirely**! A virtual route will automatically be generated for you to serve as an anchor for your code split files. This virtual route will live directly in the generated route tree file.\n\n**Before (Virtual Routes)**\n\n```tsx\n// src/routes/posts.tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts')({\n // Hello?\n})\n```\n\n```tsx\n// src/routes/posts.lazy.tsx\nimport { createLazyFileRoute } from '@tanstack/react-router'\n\nexport const Route = createLazyFileRoute('/posts')({\n component: Posts,\n})\n\nfunction Posts() {\n // ...\n}\n```\n\n**After (Virtual Routes)**\n\n```tsx\n// src/routes/posts.lazy.tsx\nimport { createLazyFileRoute } from '@tanstack/react-router'\n\nexport const Route = createLazyFileRoute('/posts')({\n component: Posts,\n})\n\nfunction Posts() {\n // ...\n}\n```\n\nTada! \uD83C\uDF89\n\n## Code-Based Splitting\n\nIf you are using code-based routing, you can still code-split your routes using the `Route.lazy()` method and the `createLazyRoute` function. You'll need to split your route configuration into two parts:\n\nCreate a lazy route using the `createLazyRoute` function.\n\n```tsx\n// src/posts.lazy.tsx\nexport const Route = createLazyRoute('/posts')({\n component: MyComponent,\n})\n\nfunction MyComponent() {\n return <div>My Component</div>\n}\n```\n\nThen, call the `.lazy` method on the route definition in your `app.tsx` to import the lazy/code-split route with the non-critical route configuration.\n\n```tsx\n// src/app.tsx\nconst postsRoute = createRoute({\n getParentRoute: () => rootRoute,\n path: '/posts',\n}).lazy(() => import('./posts.lazy').then((d) => d.Route))\n```\n\n## Data Loader Splitting\n\n**Be warned!!!** Splitting a route loader is a dangerous game.\n\nIt can be a powerful tool to reduce bundle size, but it comes with a cost as mentioned in the [How does TanStack Router split code?](#how-does-tanstack-router-split-code) section.\n\nYou can code split your data loading logic using the Route's `loader` option. While this process makes it difficult to maintain type-safety with the parameters passed to your loader, you can always use the generic `LoaderContext` type to get you most of the way there:\n\n```tsx\nimport { lazyFn } from '@tanstack/react-router'\n\nconst route = createRoute({\n path: '/my-route',\n component: MyComponent,\n loader: lazyFn(() => import('./loader'), 'loader'),\n})\n\n// In another file...a\nexport const loader = async (context: LoaderContext) => {\n /// ...\n}\n```\n\nIf you are using file-based routing, you'll only be able to split your `loader` if you are using [Automatic Code Splitting](#using-automatic-code-splitting) with customized bundling options.\n\n## Manually accessing Route APIs in other files with the `getRouteApi` helper\n\nAs you might have guessed, placing your component code in a separate file than your route can make it difficult to consume the route itself. To help with this, TanStack Router exports a handy `getRouteApi` function that you can use to access a route's type-safe APIs in a file without importing the route itself.\n\n- `my-route.tsx`\n\n```tsx\nimport { createRoute } from '@tanstack/react-router'\nimport { MyComponent } from './MyComponent'\n\nconst route = createRoute({\n path: '/my-route',\n loader: () => ({\n foo: 'bar',\n }),\n component: MyComponent,\n})\n```\n\n- `MyComponent.tsx`\n\n```tsx\nimport { getRouteApi } from '@tanstack/react-router'\n\nconst route = getRouteApi('/my-route')\n\nexport function MyComponent() {\n const loaderData = route.useLoaderData()\n // ^? { foo: string }\n\n return <div>...</div>\n}\n```\n\nThe `getRouteApi` function is useful for accessing other type-safe APIs:\n\n- `useLoaderData`\n- `useLoaderDeps`\n- `useMatch`\n- `useParams`\n- `useRouteContext`\n- `useSearch`\n\n# Creating a Router\n\n## The `Router` Class\n\nWhen you're ready to start using your router, you'll need to create a new `Router` instance. The router instance is the core brains of TanStack Router and is responsible for managing the route tree, matching routes, and coordinating navigations and route transitions. It also serves as a place to configure router-wide settings.\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n // ...\n})\n```\n\n## Route Tree\n\nYou'll probably notice quickly that the `Router` constructor requires a `routeTree` option. This is the route tree that the router will use to match routes and render components.\n\nWhether you used [file-based routing](../routing/file-based-routing.md) or [code-based routing](../routing/code-based-routing.md), you'll need to pass your route tree to the `createRouter` function:\n\n### Filesystem Route Tree\n\nIf you used our recommended file-based routing, then it's likely your generated route tree file was created at the default `src/routeTree.gen.ts` location. If you used a custom location, then you'll need to import your route tree from that location.\n\n```tsx\nimport { routeTree } from './routeTree.gen'\n```\n\n### Code-Based Route Tree\n\nIf you used code-based routing, then you likely created your route tree manually using the root route's `addChildren` method:\n\n```tsx\nconst routeTree = rootRoute.addChildren([\n // ...\n])\n```\n\n## Router Type Safety\n\n> [!IMPORTANT]\n> DO NOT SKIP THIS SECTION! \u26A0\uFE0F\n\nTanStack Router provides amazing support for TypeScript, even for things you wouldn't expect like bare imports straight from the library! To make this possible, you must register your router's types using TypeScripts' [Declaration Merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html) feature. This is done by extending the `Register` interface on `@tanstack/react-router` with a `router` property that has the type of your `router` instance:\n\n```tsx\ndeclare module '@tanstack/react-router' {\n interface Register {\n // This infers the type of our router and registers it across your entire project\n router: typeof router\n }\n}\n```\n\nWith your router registered, you'll now get type-safety across your entire project for anything related to routing.\n\n## 404 Not Found Route\n\nAs promised in earlier guides, we'll now cover the `notFoundRoute` option. This option is used to configure a route that will render when no other suitable match is found. This is useful for rendering a 404 page or redirecting to a default route.\n\nIf you are using either file-based or code-based routing, then you'll need to add a `notFoundComponent` key to `createRootRoute`:\n\n```tsx\nexport const Route = createRootRoute({\n component: () => (\n // ...\n ),\n notFoundComponent: () => <div>404 Not Found</div>,\n});\n```\n\n## Other Options\n\nThere are many other options that can be passed to the `Router` constructor. You can find a full list of them in the [API Reference](../api/router/RouterOptionsType.md).\n\n# Custom Link\n\nWhile repeating yourself can be acceptable in many situations, you might find that you do it too often. At times, you may want to create cross-cutting components with additional behavior or styles. You might also consider using third-party libraries in combination with TanStack Router's type safety.\n\n## `createLink` for cross-cutting concerns\n\n`createLink` creates a custom `Link` component with the same type parameters as `Link`. This means you can create your own component which provides the same type safety and typescript performance as `Link`.\n\n### Basic example\n\nIf you want to create a basic custom link component, you can do so with the following:\n\n[//]: # 'BasicExampleImplementation'\n\n```tsx\nimport * as React from 'react'\nimport { createLink, LinkComponent } from '@tanstack/react-router'\n\ninterface BasicLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n // Add any additional props you want to pass to the anchor element\n}\n\nconst BasicLinkComponent = React.forwardRef<HTMLAnchorElement, BasicLinkProps>(\n (props, ref) => {\n return (\n <a ref={ref} {...props} className={'block px-3 py-2 text-blue-700'} />\n )\n },\n)\n\nconst CreatedLinkComponent = createLink(BasicLinkComponent)\n\nexport const CustomLink: LinkComponent<typeof BasicLinkComponent> = (props) => {\n return <CreatedLinkComponent preload={'intent'} {...props} />\n}\n```\n\n[//]: # 'BasicExampleImplementation'\n\nYou can then use your newly created `Link` component as any other `Link`\n\n```tsx\n<CustomLink to={'/dashboard/invoices/$invoiceId'} params={{ invoiceId: 0 }} />\n```\n\n[//]: # 'ExamplesUsingThirdPartyLibs'\n\n## `createLink` with third party libraries\n\nHere are some examples of how you can use `createLink` with third-party libraries.\n\n### React Aria Components example\n\nReact Aria Components v1.11.0 and later works with TanStack Router's `preload (intent)` prop. Use `createLink` to wrap each React Aria component that you use as a link.\n\n```tsx\nimport { createLink } from '@tanstack/react-router'\nimport { Link as RACLink, MenuItem } from 'react-aria-components'\n\nexport const Link = createLink(RACLink)\nexport const MenuItemLink = createLink(MenuItem)\n```\n\nTo use React Aria's render props, including the `className`, `style`, and `children` functions, create a wrapper component and pass that to `createLink`.\n\n```tsx\nimport { createLink } from '@tanstack/react-router'\nimport { Link as RACLink, type LinkProps } from 'react-aria-components'\n\ninterface MyLinkProps extends LinkProps {\n // your props\n}\n\nfunction MyLink(props: MyLinkProps) {\n return (\n <RACLink\n {...props}\n style={({ isHovered }) => ({\n color: isHovered ? 'red' : 'blue',\n })}\n />\n )\n}\n\nexport const Link = createLink(MyLink)\n```\n\n### Chakra UI example\n\n```tsx\nimport * as React from 'react'\nimport { createLink, LinkComponent } from '@tanstack/react-router'\nimport { Link } from '@chakra-ui/react'\n\ninterface ChakraLinkProps\n extends Omit<React.ComponentPropsWithoutRef<typeof Link>, 'href'> {\n // Add any additional props you want to pass to the link\n}\n\nconst ChakraLinkComponent = React.forwardRef<\n HTMLAnchorElement,\n ChakraLinkProps\n>((props, ref) => {\n return <Link ref={ref} {...props} />\n})\n\nconst CreatedLinkComponent = createLink(ChakraLinkComponent)\n\nexport const CustomLink: LinkComponent<typeof ChakraLinkComponent> = (\n props,\n) => {\n return (\n <CreatedLinkComponent\n textDecoration={'underline'}\n _hover={{ textDecoration: 'none' }}\n _focus={{ textDecoration: 'none' }}\n preload={'intent'}\n {...props}\n />\n )\n}\n```\n\n### MUI example\n\nThere is an [example](https://github.com/TanStack/router/tree/main/examples/react/start-material-ui) available which uses these patterns.\n\n#### `Link`\n\nIf the MUI `Link` should simply behave like the router `Link`, it can be just wrapped with `createLink`:\n\n```tsx\nimport { createLink } from '@tanstack/react-router'\nimport { Link } from '@mui/material'\n\nexport const CustomLink = createLink(Link)\n```\n\nIf the `Link` should be customized this approach can be used:\n\n```tsx\nimport React from 'react'\nimport { createLink } from '@tanstack/react-router'\nimport { Link } from '@mui/material'\nimport type { LinkProps } from '@mui/material'\nimport type { LinkComponent } from '@tanstack/react-router'\n\ninterface MUILinkProps extends LinkProps {\n // Add any additional props you want to pass to the Link\n}\n\nconst MUILinkComponent = React.forwardRef<HTMLAnchorElement, MUILinkProps>(\n (props, ref) => <Link ref={ref} {...props} />,\n)\n\nconst CreatedLinkComponent = createLink(MUILinkComponent)\n\nexport const CustomLink: LinkComponent<typeof MUILinkComponent> = (props) => {\n return <CreatedLinkComponent preload={'intent'} {...props} />\n}\n\n// Can also be styled\n```\n\n#### `Button`\n\nIf a `Button` should be used as a router `Link`, the `component` should be set as `a`:\n\n```tsx\nimport React from 'react'\nimport { createLink } from '@tanstack/react-router'\nimport { Button } from '@mui/material'\nimport type { ButtonProps } from '@mui/material'\nimport type { LinkComponent } from '@tanstack/react-router'\n\ninterface MUIButtonLinkProps extends ButtonProps<'a'> {\n // Add any additional props you want to pass to the Button\n}\n\nconst MUIButtonLinkComponent = React.forwardRef<\n HTMLAnchorElement,\n MUIButtonLinkProps\n>((props, ref) => <Button ref={ref} component=\"a\" {...props} />)\n\nconst CreatedButtonLinkComponent = createLink(MUIButtonLinkComponent)\n\nexport const CustomButtonLink: LinkComponent<typeof MUIButtonLinkComponent> = (\n props,\n) => {\n return <CreatedButtonLinkComponent preload={'intent'} {...props} />\n}\n```\n\n#### Usage with `styled`\n\nAny of these MUI approaches can then be used with `styled`:\n\n```tsx\nimport { css, styled } from '@mui/material'\nimport { CustomLink } from './CustomLink'\n\nconst StyledCustomLink = styled(CustomLink)(\n ({ theme }) => css`\n color: ${theme.palette.common.white};\n `,\n)\n```\n\n### Mantine example\n\n```tsx\nimport * as React from 'react'\nimport { createLink, LinkComponent } from '@tanstack/react-router'\nimport { Anchor, AnchorProps } from '@mantine/core'\n\ninterface MantineAnchorProps extends Omit<AnchorProps, 'href'> {\n // Add any additional props you want to pass to the anchor\n}\n\nconst MantineLinkComponent = React.forwardRef<\n HTMLAnchorElement,\n MantineAnchorProps\n>((props, ref) => {\n return <Anchor ref={ref} {...props} />\n})\n\nconst CreatedLinkComponent = createLink(MantineLinkComponent)\n\nexport const CustomLink: LinkComponent<typeof MantineLinkComponent> = (\n props,\n) => {\n return <CreatedLinkComponent preload=\"intent\" {...props} />\n}\n```\n\n[//]: # 'ExamplesUsingThirdPartyLibs'\n\n# Custom Search Param Serialization\n\nBy default, TanStack Router parses and serializes your URL Search Params automatically using `JSON.stringify` and `JSON.parse`. This process involves escaping and unescaping the search string, which is a common practice for URL search params, in addition to the serialization and deserialization of the search object.\n\nFor instance, using the default configuration, if you have the following search object:\n\n```tsx\nconst search = {\n page: 1,\n sort: 'asc',\n filters: { author: 'tanner', min_words: 800 },\n}\n```\n\nIt would be serialized and escaped into the following search string:\n\n```txt\n?page=1&sort=asc&filters=%7B%22author%22%3A%22tanner%22%2C%22min_words%22%3A800%7D\n```\n\nWe can implement the default behavior with the following code:\n\n```tsx\nimport {\n createRouter,\n parseSearchWith,\n stringifySearchWith,\n} from '@tanstack/react-router'\n\nconst router = createRouter({\n // ...\n parseSearch: parseSearchWith(JSON.parse),\n stringifySearch: stringifySearchWith(JSON.stringify),\n})\n```\n\nHowever, this default behavior may not be suitable for all use cases. For example, you may want to use a different serialization format, such as base64 encoding, or you may want to use a purpose-built serialization/deserialization library, like [query-string](https://github.com/sindresorhus/query-string), [JSURL2](https://github.com/wmertens/jsurl2), or [Zipson](https://jgranstrom.github.io/zipson/).\n\nThis can be achieved by providing your own serialization and deserialization functions to the `parseSearch` and `stringifySearch` options in the [`Router`](../api/router/RouterOptionsType.md#stringifysearch-method) configuration. When doing this, you can utilize TanStack Router's built-in helper functions, `parseSearchWith` and `stringifySearchWith`, to simplify the process.\n\n> [!TIP]\n> An important aspect of serialization and deserialization, is that you are able to get the same object back after deserialization. This is important because if the serialization and deserialization process is not done correctly, you may lose some information. For example, if you are using a library that does not support nested objects, you may lose the nested object when deserializing the search string.\n\n![Diagram showing idempotent nature of URL search param serialization and deserialization](https://raw.githubusercontent.com/TanStack/router/main/docs/router/assets/search-serialization-deserialization-idempotency.jpg)\n\nHere are some examples of how you can customize the search param serialization in TanStack Router:\n\n## Using Base64\n\nIt's common to base64 encode your search params to achieve maximum compatibility across browsers and URL unfurlers, etc. This can be done with the following code:\n\n```tsx\nimport {\n Router,\n parseSearchWith,\n stringifySearchWith,\n} from '@tanstack/react-router'\n\nconst router = createRouter({\n parseSearch: parseSearchWith((value) => JSON.parse(decodeFromBinary(value))),\n stringifySearch: stringifySearchWith((value) =>\n encodeToBinary(JSON.stringify(value)),\n ),\n})\n\nfunction decodeFromBinary(str: string): string {\n return decodeURIComponent(\n Array.prototype.map\n .call(atob(str), function (c) {\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)\n })\n .join(''),\n )\n}\n\nfunction encodeToBinary(str: string): string {\n return btoa(\n encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {\n return String.fromCharCode(parseInt(p1, 16))\n }),\n )\n}\n```\n\n> [\u26A0\uFE0F Why does this snippet not use atob/btoa?](#safe-binary-encodingdecoding)\n\nSo, if we were to turn the previous object into a search string using this configuration, it would look like this:\n\n```txt\n?page=1&sort=asc&filters=eyJhdXRob3IiOiJ0YW5uZXIiLCJtaW5fd29yZHMiOjgwMH0%3D\n```\n\n> [!WARNING]\n> If you are serializing user input into Base64, you run the risk of causing a collision with the URL deserialization. This can lead to unexpected behavior, such as the URL not being parsed correctly or being interpreted as a different value. To avoid this, you should encode the search params using a safe binary encoding/decoding method (see below).\n\n## Using the query-string library\n\nThe [query-string](https://github.com/sindresorhus/query-string) library is a popular for being able to reliably parse and stringify query strings. You can use it to customize the serialization format of your search params. This can be done with the following code:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\nimport qs from 'query-string'\n\nconst router = createRouter({\n // ...\n stringifySearch: stringifySearchWith((value) =>\n qs.stringify(value, {\n // ...options\n }),\n ),\n parseSearch: parseSearchWith((value) =>\n qs.parse(value, {\n // ...options\n }),\n ),\n})\n```\n\nSo, if we were to turn the previous object into a search string using this configuration, it would look like this:\n\n```txt\n?page=1&sort=asc&filters=author%3Dtanner%26min_words%3D800\n```\n\n## Using the JSURL2 library\n\n[JSURL2](https://github.com/wmertens/jsurl2) is a non-standard library that can compress URLs while still maintaining readability. This can be done with the following code:\n\n```tsx\nimport {\n Router,\n parseSearchWith,\n stringifySearchWith,\n} from '@tanstack/react-router'\nimport { parse, stringify } from 'jsurl2'\n\nconst router = createRouter({\n // ...\n parseSearch: parseSearchWith(parse),\n stringifySearch: stringifySearchWith(stringify),\n})\n```\n\nSo, if we were to turn the previous object into a search string using this configuration, it would look like this:\n\n```txt\n?page=1&sort=asc&filters=(author~tanner~min*_words~800)~\n```\n\n## Using the Zipson library\n\n[Zipson](https://jgranstrom.github.io/zipson/) is a very user-friendly and performant JSON compression library (both in runtime performance and the resulting compression performance). To compress your search params with it (which requires escaping/unescaping and base64 encoding/decoding them as well), you can use the following code:\n\n```tsx\nimport {\n Router,\n parseSearchWith,\n stringifySearchWith,\n} from '@tanstack/react-router'\nimport { stringify, parse } from 'zipson'\n\nconst router = createRouter({\n parseSearch: parseSearchWith((value) => parse(decodeFromBinary(value))),\n stringifySearch: stringifySearchWith((value) =>\n encodeToBinary(stringify(value)),\n ),\n})\n\nfunction decodeFromBinary(str: string): string {\n return decodeURIComponent(\n Array.prototype.map\n .call(atob(str), function (c) {\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)\n })\n .join(''),\n )\n}\n\nfunction encodeToBinary(str: string): string {\n return btoa(\n encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {\n return String.fromCharCode(parseInt(p1, 16))\n }),\n )\n}\n```\n\n> [\u26A0\uFE0F Why does this snippet not use atob/btoa?](#safe-binary-encodingdecoding)\n\nSo, if we were to turn the previous object into a search string using this configuration, it would look like this:\n\n```txt\n?page=1&sort=asc&filters=JTdCJUMyJUE4YXV0aG9yJUMyJUE4JUMyJUE4dGFubmVyJUMyJUE4JUMyJUE4bWluX3dvcmRzJUMyJUE4JUMyJUEyQ3UlN0Q%3D\n```\n\n<hr>\n\n### Safe Binary Encoding/Decoding\n\nIn the browser, the `atob` and `btoa` functions are not guaranteed to work properly with non-UTF8 characters. We recommend using these encoding/decoding utilities instead:\n\nTo encode from a string to a binary string:\n\n```typescript\nexport function encodeToBinary(str: string): string {\n return btoa(\n encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {\n return String.fromCharCode(parseInt(p1, 16))\n }),\n )\n}\n```\n\nTo decode from a binary string to a string:\n\n```typescript\nexport function decodeFromBinary(str: string): string {\n return decodeURIComponent(\n Array.prototype.map\n .call(atob(str), function (c) {\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)\n })\n .join(''),\n )\n}\n```\n\n# Data Loading\n\nData loading is a common concern for web applications and is related to routing. When loading a page for your app, it's ideal if all of the page's async requirements are fetched and fulfilled as early as possible, in parallel. The router is the best place to coordinate these async dependencies as it's usually the only place in your app that knows where users are headed before content is rendered.\n\nYou may be familiar with `getServerSideProps` from Next.js or `loader`s from Remix/React-Router. TanStack Router has similar functionality to preload/load assets on a per-route basis in parallel allowing it to render as quickly as possible as it fetches via suspense.\n\nBeyond these normal expectations of a router, TanStack Router goes above and beyond and provides **built-in SWR Caching**, a long-term in-memory caching layer for route loaders. This means that you can use TanStack Router to both preload data for your routes so they load instantaneously or temporarily cache route data for previously visited routes to use again later.\n\n## The route loading lifecycle\n\nEvery time a URL/history update is detected, the router executes the following sequence:\n\n- Route Matching (Top-Down)\n - `route.params.parse`\n - `route.validateSearch`\n- Route Pre-Loading (Serial)\n - `route.beforeLoad`\n - `route.onError`\n - `route.errorComponent` / `parentRoute.errorComponent` / `router.defaultErrorComponent`\n- Route Loading (Parallel)\n - `route.component.preload?`\n - `route.loader`\n - `route.pendingComponent` (Optional)\n - `route.component`\n - `route.onError`\n - `route.errorComponent` / `parentRoute.errorComponent` / `router.defaultErrorComponent`\n\n## To Router Cache or not to Router Cache?\n\nThere is a high possibility that TanStack's router cache will be a good fit for most smaller to medium size applications, but it's important to understand the tradeoffs of using it vs a more robust caching solution like TanStack Query:\n\nTanStack Router Cache Pros:\n\n- Built-in, easy to use, no extra dependencies\n- Handles deduping, preloading, loading, stale-while-revalidate, background refetching on a per-route basis\n- Coarse invalidation (invalidate all routes and cache at once)\n- Automatic garbage collection\n- Works great for apps that share little data between routes\n- \"Just works\" for SSR\n\nTanStack Router Cache Cons:\n\n- No persistence adapters/model\n- No shared caching/deduping between routes\n- No built-in mutation APIs (a basic `useMutation` hook is provided in many examples that may be sufficient for many use cases)\n- No built-in cache-level optimistic update APIs (you can still use ephemeral state from something like a `useMutation` hook to achieve this at the component level)\n\n> [!TIP]\n> If you know right away that you'd like to or need to use something more robust like TanStack Query, skip to the [External Data Loading](./external-data-loading.md) guide.\n\n## Using the Router Cache\n\nThe router cache is built-in and is as easy as returning data from any route's `loader` function. Let's learn how!\n\n## Route `loader`s\n\nRoute `loader` functions are called when a route match is loaded. They are called with a single parameter which is an object containing many helpful properties. We'll go over those in a bit, but first, let's look at an example of a route `loader` function:\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n})\n```\n\n## `loader` Parameters\n\nThe `loader` function receives a single object with the following properties:\n\n- `abortController` - The route's abortController. Its signal is cancelled when the route is unloaded or when the Route is no longer relevant and the current invocation of the `loader` function becomes outdated.\n- `cause` - The cause of the current route match. Can be either one of the following:\n - `enter` - When the route is matched and loaded after not being matched in the previous location.\n - `preload` - When the route is being preloaded.\n - `stay` - When the route is matched and loaded after being matched in the previous location.\n- `context` - The route's context object, which is a merged union of:\n - Parent route context\n - This route's context as provided by the `beforeLoad` option\n- `deps` - The object value returned from the `Route.loaderDeps` function. If `Route.loaderDeps` is not defined, an empty object will be provided instead.\n- `location` - The current location\n- `params` - The route's path params\n- `parentMatchPromise` - `Promise<RouteMatch>` (`undefined` for the root route)\n- `preload` - Boolean which is `true` when the route is being preloaded instead of loaded\n- `route` - The route itself\n\nUsing these parameters, we can do a lot of cool things, but first, let's take a look at how we can control it and when the `loader` function is called.\n\n## Consuming data from `loader`s\n\nTo consume data from a `loader`, use the `useLoaderData` hook defined on your Route object.\n\n```tsx\nconst posts = Route.useLoaderData()\n```\n\nIf you don't have ready access to your route object (i.e. you're deep in the component tree for the current route), you can use `getRouteApi` to access the same hook (as well as the other hooks on the Route object). This should be preferred over importing the Route object, which is likely to create circular dependencies.\n\n```tsx\nimport { getRouteApi } from '@tanstack/react-router'\n\n// in your component\n\nconst routeApi = getRouteApi('/posts')\nconst data = routeApi.useLoaderData()\n```\n\n## Dependency-based Stale-While-Revalidate Caching\n\nTanStack Router provides a built-in Stale-While-Revalidate caching layer for route loaders that is keyed on the dependencies of a route:\n\n- The route's fully parsed pathname\n - e.g. `/posts/1` vs `/posts/2`\n- Any additional dependencies provided by the `loaderDeps` option\n - e.g. `loaderDeps: ({ search: { pageIndex, pageSize } }) => ({ pageIndex, pageSize })`\n\nUsing these dependencies as keys, TanStack Router will cache the data returned from a route's `loader` function and use it to fulfill subsequent requests for the same route match. This means that if a route's data is already in the cache, it will be returned immediately, then **potentially** be refetched in the background depending on the \"freshness\" of the data.\n\n### Key options\n\nTo control router dependencies and \"freshness\", TanStack Router provides a plethora of options to control the keying and caching behavior of your route loaders. Let's take a look at them in the order that you are most likely to use them:\n\n- `routeOptions.loaderDeps`\n - A function that supplies you the search params for a router and returns an object of dependencies for use in your `loader` function. When these deps changed from navigation to navigation, it will cause the route to reload regardless of `staleTime`s. The deps are compared using a deep equality check.\n- `routeOptions.staleTime`\n- `routerOptions.defaultStaleTime`\n - The number of milliseconds that a route's data should be considered fresh when attempting to load.\n- `routeOptions.preloadStaleTime`\n- `routerOptions.defaultPreloadStaleTime`\n - The number of milliseconds that a route's data should be considered fresh attempting to preload.\n- `routeOptions.gcTime`\n- `routerOptions.defaultGcTime`\n - The number of milliseconds that a route's data should be kept in the cache before being garbage collected.\n- `routeOptions.shouldReload`\n - A function that receives the same `beforeLoad` and `loaderContext` parameters and returns a boolean indicating if the route should reload. This offers one more level of control over when a route should reload beyond `staleTime` and `loaderDeps` and can be used to implement patterns similar to Remix's `shouldLoad` option.\n\n### \u26A0\uFE0F Some Important Defaults\n\n- By default, the `staleTime` is set to `0`, meaning that the route's data will always be considered stale and will always be reloaded in the background when the route is rematched.\n- By default, a previously preloaded route is considered fresh for **30 seconds**. This means if a route is preloaded, then preloaded again within 30 seconds, the second preload will be ignored. This prevents unnecessary preloads from happening too frequently. **When a route is loaded normally, the standard `staleTime` is used.**\n- By default, the `gcTime` is set to **30 minutes**, meaning that any route data that has not been accessed in 30 minutes will be garbage collected and removed from the cache.\n- `router.invalidate()` will force all active routes to reload their loaders immediately and mark every cached route's data as stale.\n\n### Using `loaderDeps` to access search params\n\nImagine a `/posts` route supports some pagination via search params `offset` and `limit`. For the cache to uniquely store this data, we need to access these search params via the `loaderDeps` function. By explicitly identifying them, each route match for `/posts` with different `offset` and `limit` won't get mixed up!\n\nOnce we have these deps in place, the route will always reload when the deps change.\n\n```tsx\n// /routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loaderDeps: ({ search: { offset, limit } }) => ({ offset, limit }),\n loader: ({ deps: { offset, limit } }) =>\n fetchPosts({\n offset,\n limit,\n }),\n})\n```\n\n### Using `staleTime` to control how long data is considered fresh\n\nBy default, `staleTime` for navigations is set to `0`ms (and 30 seconds for preloads) which means that the route's data will always be considered stale and will always be reloaded in the background when the route is matched and navigated to.\n\n**This is a good default for most use cases, but you may find that some route data is more static or potentially expensive to load.** In these cases, you can use the `staleTime` option to control how long the route's data is considered fresh for navigations. Let's take a look at an example:\n\n```tsx\n// /routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n // Consider the route's data fresh for 10 seconds\n staleTime: 10_000,\n})\n```\n\nBy passing `10_000` to the `staleTime` option, we are telling the router to consider the route's data fresh for 10 seconds. This means that if the user navigates to `/posts` from `/about` within 10 seconds of the last loader result, the route's data will not be reloaded. If the user then navigates to `/posts` from `/about` after 10 seconds, the route's data will be reloaded **in the background**.\n\n## Turning off stale-while-revalidate caching\n\nTo disable stale-while-revalidate caching for a route, set the `staleTime` option to `Infinity`:\n\n```tsx\n// /routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n staleTime: Infinity,\n})\n```\n\nYou can even turn this off for all routes by setting the `defaultStaleTime` option on the router:\n\n```tsx\nconst router = createRouter({\n routeTree,\n defaultStaleTime: Infinity,\n})\n```\n\n## Using `shouldReload` and `gcTime` to opt-out of caching\n\nSimilar to Remix's default functionality, you may want to configure a route to only load on entry or when critical loader deps change. You can do this by using the `gcTime` option combined with the `shouldReload` option, which accepts either a `boolean` or a function that receives the same `beforeLoad` and `loaderContext` parameters and returns a boolean indicating if the route should reload.\n\n```tsx\n// /routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loaderDeps: ({ search: { offset, limit } }) => ({ offset, limit }),\n loader: ({ deps }) => fetchPosts(deps),\n // Do not cache this route's data after it's unloaded\n gcTime: 0,\n // Only reload the route when the user navigates to it or when deps change\n shouldReload: false,\n})\n```\n\n### Opting out of caching while still preloading\n\nEven though you may opt-out of short-term caching for your route data, you can still get the benefits of preloading! With the above configuration, preloading will still \"just work\" with the default `preloadGcTime`. This means that if a route is preloaded, then navigated to, the route's data will be considered fresh and will not be reloaded.\n\nTo opt out of preloading, don't turn it on via the `routerOptions.defaultPreload` or `routeOptions.preload` options.\n\n## Passing all loader events to an external cache\n\nWe break down this use case in the [External Data Loading](./external-data-loading.md) page, but if you'd like to use an external cache like TanStack Query, you can do so by passing all loader events to your external cache. As long as you are using the defaults, the only change you'll need to make is to set the `defaultPreloadStaleTime` option on the router to `0`:\n\n```tsx\nconst router = createRouter({\n routeTree,\n defaultPreloadStaleTime: 0,\n})\n```\n\nThis will ensure that every preload, load, and reload event will trigger your `loader` functions, which can then be handled and deduped by your external cache.\n\n## Using Router Context\n\nThe `context` argument passed to the `loader` function is an object containing a merged union of:\n\n- Parent route context\n- This route's context as provided by the `beforeLoad` option\n\nStarting at the very top of the router, you can pass an initial context to the router via the `context` option. This context will be available to all routes in the router and get copied and extended by each route as they are matched. This happens by passing a context to a route via the `beforeLoad` option. This context will be available to all the route's child routes. The resulting context will be available to the route's `loader` function.\n\nIn this example, we'll create a function in our route context to fetch posts, then use it in our `loader` function.\n\n> \uD83E\uDDE0 Context is a powerful tool for dependency injection. You can use it to inject services, hooks, and other objects into your router and routes. You can also additively pass data down the route tree at every route using a route's `beforeLoad` option.\n\n- `/utils/fetchPosts.tsx`\n\n```tsx\nexport const fetchPosts = async () => {\n const res = await fetch(`/api/posts?page=${pageIndex}`)\n if (!res.ok) throw new Error('Failed to fetch posts')\n return res.json()\n}\n```\n\n- `/routes/__root.tsx`\n\n```tsx\nimport { createRootRouteWithContext } from '@tanstack/react-router'\n\n// Create a root route using the createRootRouteWithContext<{...}>() function and pass it whatever types you would like to be available in your router context.\nexport const Route = createRootRouteWithContext<{\n fetchPosts: typeof fetchPosts\n}>()() // NOTE: the double call is on purpose, since createRootRouteWithContext is a factory ;)\n```\n\n- `/routes/posts.tsx`\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\n// Notice how our postsRoute references context to get our fetchPosts function\n// This can be a powerful tool for dependency injection across your router\n// and routes.\nexport const Route = createFileRoute('/posts')({\n loader: ({ context: { fetchPosts } }) => fetchPosts(),\n})\n```\n\n- `/router.tsx`\n\n```tsx\nimport { routeTree } from './routeTree.gen'\n\n// Use your routerContext to create a new router\n// This will require that you fullfil the type requirements of the routerContext\nconst router = createRouter({\n routeTree,\n context: {\n // Supply the fetchPosts function to the router context\n fetchPosts,\n },\n})\n```\n\n## Using Path Params\n\nTo use path params in your `loader` function, access them via the `params` property on the function's parameters. Here's an example:\n\n```tsx\n// routes/posts.$postId.tsx\nexport const Route = createFileRoute('/posts/$postId')({\n loader: ({ params: { postId } }) => fetchPostById(postId),\n})\n```\n\n## Using Route Context\n\nPassing down global context to your router is great, but what if you want to provide context that is specific to a route? This is where the `beforeLoad` option comes in. The `beforeLoad` option is a function that runs right before attempting to load a route and receives the same parameters as `loader`. Beyond its ability to redirect potential matches, block loader requests, etc, it can also return an object that will be merged into the route's context. Let's take a look at an example where we inject some data into our route context via the `beforeLoad` option:\n\n```tsx\n// /routes/posts.tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts')({\n // Pass the fetchPosts function to the route context\n beforeLoad: () => ({\n fetchPosts: () => console.info('foo'),\n }),\n loader: ({ context: { fetchPosts } }) => {\n fetchPosts() // 'foo'\n\n // ...\n },\n})\n```\n\n## Using Search Params in Loaders\n\n> \u2753 But wait Tanner... where the heck are my search params?!\n\nYou might be here wondering why `search` isn't directly available in the `loader` function's parameters. We've purposefully designed it this way to help you succeed. Let's take a look at why:\n\n- Search Parameters being used in a loader function are a very good indicator that those search params should also be used to uniquely identify the data being loaded. For example, you may have a route that uses a search param like `pageIndex` that uniquely identifies the data held inside of the route match. Or, imagine a `/users/user` route that uses the search param `userId` to identify a specific user in your application, you might model your url like this: `/users/user?userId=123`. This means that your `user` route would need some extra help to identify a specific user.\n- Directly accessing search params in a loader function can lead to bugs in caching and preloading where the data being loaded is not unique to the current URL pathname and search params. For example, you might ask your `/posts` route to preload page 2's results, but without the distinction of pages in your route configuration, you will end up fetching, storing and displaying page 2's data on your `/posts` or `?page=1` screen instead of it preloading in the background!\n- Placing a threshold between search parameters and the loader function allows the router to understand your dependencies and reactivity.\n\n```tsx\n// /routes/users.user.tsx\nexport const Route = createFileRoute('/users/user')({\n validateSearch: (search) =>\n search as {\n userId: string\n },\n loaderDeps: ({ search: { userId } }) => ({\n userId,\n }),\n loader: async ({ deps: { userId } }) => getUser(userId),\n})\n```\n\n### Accessing Search Params via `routeOptions.loaderDeps`\n\n```tsx\n// /routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n // Use zod to validate and parse the search params\n validateSearch: z.object({\n offset: z.number().int().nonnegative().catch(0),\n }),\n // Pass the offset to your loader deps via the loaderDeps function\n loaderDeps: ({ search: { offset } }) => ({ offset }),\n // Use the offset from context in the loader function\n loader: async ({ deps: { offset } }) =>\n fetchPosts({\n offset,\n }),\n})\n```\n\n## Using the Abort Signal\n\nThe `abortController` property of the `loader` function is an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController). Its signal is cancelled when the route is unloaded or when the `loader` call becomes outdated. This is useful for cancelling network requests when the route is unloaded or when the route's params change. Here is an example using it with a fetch call:\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: ({ abortController }) =>\n fetchPosts({\n // Pass this to an underlying fetch call or anything that supports signals\n signal: abortController.signal,\n }),\n})\n```\n\n## Using the `preload` flag\n\nThe `preload` property of the `loader` function is a boolean which is `true` when the route is being preloaded instead of loaded. Some data loading libraries may handle preloading differently than a standard fetch, so you may want to pass `preload` to your data loading library, or use it to execute the appropriate data loading logic:\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: async ({ preload }) =>\n fetchPosts({\n maxAge: preload ? 10_000 : 0, // Preloads should hang around a bit longer\n }),\n})\n```\n\n## Handling Slow Loaders\n\nIdeally most route loaders can resolve their data within a short moment, removing the need to render a placeholder spinner and simply rely on suspense to render the next route when it's completely ready. When critical data that is required to render a route's component is slow though, you have 2 options:\n\n- Split up your fast and slow data into separate promises and `defer` the slow data until after the fast data is loaded (see the [Deferred Data Loading](./deferred-data-loading.md) guide).\n- Show a pending component after an optimistic suspense threshold until all of the data is ready (See below).\n\n## Showing a pending component\n\n**By default, TanStack Router will show a pending component for loaders that take longer than 1 second to resolve.** This is an optimistic threshold that can be configured via:\n\n- `routeOptions.pendingMs` or\n- `routerOptions.defaultPendingMs`\n\nWhen the pending time threshold is exceeded, the router will render the `pendingComponent` option of the route, if configured.\n\n## Avoiding Pending Component Flash\n\nIf you're using a pending component, the last thing you want is for your pending time threshold to be met, then have your data resolve immediately after, resulting in a jarring flash of your pending component. To avoid this, **TanStack Router by default will show your pending component for at least 500ms**. This is an optimistic threshold that can be configured via:\n\n- `routeOptions.pendingMinMs` or\n- `routerOptions.defaultPendingMinMs`\n\n## Handling Errors\n\nTanStack Router provides a few ways to handle errors that occur during the route loading lifecycle. Let's take a look at them.\n\n### Handling Errors with `routeOptions.onError`\n\nThe `routeOptions.onError` option is a function that is called when an error occurs during the route loading.\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n onError: ({ error }) => {\n // Log the error\n console.error(error)\n },\n})\n```\n\n### Handling Errors with `routeOptions.onCatch`\n\nThe `routeOptions.onCatch` option is a function that is called whenever an error was caught by the router's CatchBoundary.\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n onCatch: ({ error, errorInfo }) => {\n // Log the error\n console.error(error)\n },\n})\n```\n\n### Handling Errors with `routeOptions.errorComponent`\n\nThe `routeOptions.errorComponent` option is a component that is rendered when an error occurs during the route loading or rendering lifecycle. It is rendered with the following props:\n\n- `error` - The error that occurred\n- `reset` - A function to reset the internal `CatchBoundary`\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n errorComponent: ({ error }) => {\n // Render an error message\n return <div>{error.message}</div>\n },\n})\n```\n\nThe `reset` function can be used to allow the user to retry rendering the error boundaries normal children:\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n errorComponent: ({ error, reset }) => {\n return (\n <div>\n {error.message}\n <button\n onClick={() => {\n // Reset the router error boundary\n reset()\n }}\n >\n retry\n </button>\n </div>\n )\n },\n})\n```\n\nIf the error was the result of a route load, you should instead call `router.invalidate()`, which will coordinate both a router reload and an error boundary reset:\n\n```tsx\n// routes/posts.tsx\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n errorComponent: ({ error, reset }) => {\n const router = useRouter()\n\n return (\n <div>\n {error.message}\n <button\n onClick={() => {\n // Invalidate the route to reload the loader, which will also reset the error boundary\n router.invalidate()\n }}\n >\n retry\n </button>\n </div>\n )\n },\n})\n```\n\n### Using the default `ErrorComponent`\n\nTanStack Router provides a default `ErrorComponent` that is rendered when an error occurs during the route loading or rendering lifecycle. If you choose to override your routes' error components, it's still wise to always fall back to rendering any uncaught errors with the default `ErrorComponent`:\n\n```tsx\n// routes/posts.tsx\nimport { createFileRoute, ErrorComponent } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts')({\n loader: () => fetchPosts(),\n errorComponent: ({ error }) => {\n if (error instanceof MyCustomError) {\n // Render a custom error message\n return <div>{error.message}</div>\n }\n\n // Fallback to the default ErrorComponent\n return <ErrorComponent error={error} />\n },\n})\n```\n\n# Data Mutations\n\nSince TanStack router does not store or cache data, it's role in data mutation is slim to none outside of reacting to potential URL side-effects from external mutation events. That said, we've compiled a list of mutation-related features you might find useful and libraries that implement them.\n\nLook for and use mutation utilities that support:\n\n- Handling and caching submission state\n- Providing both local and global optimistic UI support\n- Built-in hooks to wire up invalidation (or automatically support it)\n- Handling multiple in-flight mutations at once\n- Organizing mutation state as a globally accessible resource\n- Submission state history and garbage collection\n\nSome suggested libraries:\n\n- [TanStack Query](https://tanstack.com/query/latest/docs/react/guides/mutations)\n- [SWR](https://swr.vercel.app/)\n- [RTK Query](https://redux-toolkit.js.org/rtk-query/overview)\n- [urql](https://formidable.com/open-source/urql/)\n- [Relay](https://relay.dev/)\n- [Apollo](https://www.apollographql.com/docs/react/)\n\nOr, even...\n\n- [Zustand](https://zustand-demo.pmnd.rs/)\n- [Jotai](https://jotai.org/)\n- [Recoil](https://recoiljs.org/)\n- [Redux](https://redux.js.org/)\n\nSimilar to data fetching, mutation state isn't a one-size-fits-all solution, so you'll need to pick a solution that fits your needs and your team's needs. We recommend trying out a few different solutions and seeing what works best for you.\n\n> \u26A0\uFE0F Still here? Submission state is an interesting topic when it comes to persistence. Do you keep every mutation around forever? How do you know when to get rid of it? What if the user navigates away from the screen and then back? Let's dig in!\n\n## Invalidating TanStack Router after a mutation\n\nTanStack Router comes with short-term caching built-in. So even though we're not storing any data after a route match is unmounted, there is a high probability that if any mutations are made related to the data stored in the Router, the current route matches' data could become stale.\n\nWhen mutations related to loader data are made, we can use `router.invalidate` to force the router to reload all of the current route matches:\n\n```tsx\nconst router = useRouter()\n\nconst addTodo = async (todo: Todo) => {\n try {\n await api.addTodo()\n router.invalidate()\n } catch {\n //\n }\n}\n```\n\nInvalidating all of the current route matches happens in the background, so existing data will continue to be served until the new data is ready, just as if you were navigating to a new route.\n\nIf you want to await the invalidation until all loaders have finished, pass `{sync: true}` into `router.invalidate`:\n\n```tsx\nconst router = useRouter()\n\nconst addTodo = async (todo: Todo) => {\n try {\n await api.addTodo()\n await router.invalidate({ sync: true })\n } catch {\n //\n }\n}\n```\n\n## Long-term mutation State\n\nRegardless of the mutation library used, mutations often create state related to their submission. While most mutations are set-and-forget, some mutation states are more long-lived, either to support optimistic UI or to provide feedback to the user about the status of their submissions. Most state managers will correctly keep this submission state around and expose it to make it possible to show UI elements like loading spinners, success messages, error messages, etc.\n\nLet's consider the following interactions:\n\n- User navigates to the `/posts/123/edit` screen to edit a post\n- User edits the `123` post and upon success, sees a success message below the editor that the post was updated\n- User navigates to the `/posts` screen\n- User navigates back to the `/posts/123/edit` screen again\n\nWithout notifying your mutation management library about the route change, it's possible that your submission state could still be around and your user would still see the **\"Post updated successfully\"** message when they return to the previous screen. This is not ideal. Obviously, our intent wasn't to keep this mutation state around forever, right?!\n\n## Using mutation keys\n\nHopefully and hypothetically, the easiest way is for your mutation library to support a keying mechanism that will allow your mutations's state to be reset when the key changes:\n\n```tsx\nconst routeApi = getRouteApi('/room/$roomId/chat')\n\nfunction ChatRoom() {\n const { roomId } = routeApi.useParams()\n\n const sendMessageMutation = useCoolMutation({\n fn: sendMessage,\n // Clear the mutation state when the roomId changes\n // including any submission state\n key: ['sendMessage', roomId],\n })\n\n // Fire off a bunch of messages\n const test = () => {\n sendMessageMutation.mutate({ roomId, message: 'Hello!' })\n sendMessageMutation.mutate({ roomId, message: 'How are you?' })\n sendMessageMutation.mutate({ roomId, message: 'Goodbye!' })\n }\n\n return (\n <>\n {sendMessageMutation.submissions.map((submission) => {\n return (\n <div>\n <div>{submission.status}</div>\n <div>{submission.message}</div>\n </div>\n )\n })}\n </>\n )\n}\n```\n\n## Using the `router.subscribe` method\n\nFor libraries that don't have a keying mechanism, we'll likely need to manually reset the mutation state when the user navigates away from the screen. To solve this, we can use TanStack Router's `invalidate` and `subscribe` method to clear mutation states when the user is no longer in need of them.\n\nThe `router.subscribe` method is a function that subscribes a callback to various router events. The event in particular that we'll use here is the `onResolved` event. It's important to understand that this event is fired when the location path is _changed (not just reloaded) and has finally resolved_.\n\nThis is a great place to reset your old mutation states. Here's an example:\n\n```tsx\nconst router = createRouter()\nconst coolMutationCache = createCoolMutationCache()\n\nconst unsubscribeFn = router.subscribe('onResolved', () => {\n // Reset mutation states when the route changes\n coolMutationCache.clear()\n})\n```\n\n# Deferred Data Loading\n\nTanStack Router is designed to run loaders in parallel and wait for all of them to resolve before rendering the next route. This is great most of the time, but occasionally, you may want to show the user something sooner while the rest of the data loads in the background.\n\nDeferred data loading is a pattern that allows the router to render the next location's critical data/markup while slower, non-critical route data is resolved in the background. This process works on both the client and server (via streaming) and is a great way to improve the perceived performance of your application.\n\nIf you are using a library like [TanStack Query](https://tanstack.com/query/latest) or any other data fetching library, then deferred data loading works a bit differently. Skip ahead to the [Deferred Data Loading with External Libraries](#deferred-data-loading-with-external-libraries) section for more information.\n\n## Deferred Data Loading with `Await`\n\nTo defer slow or non-critical data, return an **unawaited/unresolved** promise anywhere in your loader response:\n\n```tsx\n// src/routes/posts.$postId.tsx\nimport { createFileRoute, defer } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async () => {\n // Fetch some slower data, but do not await it\n const slowDataPromise = fetchSlowData()\n\n // Fetch and await some data that resolves quickly\n const fastData = await fetchFastData()\n\n return {\n fastData,\n deferredSlowData: slowDataPromise,\n }\n },\n})\n```\n\nAs soon as any awaited promises are resolved, the next route will begin rendering while the deferred promises continue to resolve.\n\nIn the component, deferred promises can be resolved and utilized using the `Await` component:\n\n```tsx\n// src/routes/posts.$postId.tsx\nimport { createFileRoute, Await } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts/$postId')({\n // ...\n component: PostIdComponent,\n})\n\nfunction PostIdComponent() {\n const { deferredSlowData, fastData } = Route.useLoaderData()\n\n // do something with fastData\n\n return (\n <Await promise={deferredSlowData} fallback={<div>Loading...</div>}>\n {(data) => {\n return <div>{data}</div>\n }}\n </Await>\n )\n}\n```\n\n> [!TIP]\n> If your component is code-split, you can use the [getRouteApi function](./code-splitting.md#manually-accessing-route-apis-in-other-files-with-the-getrouteapi-helper) to avoid having to import the `Route` configuration to get access to the typed `useLoaderData()` hook.\n\nThe `Await` component resolves the promise by triggering the nearest suspense boundary until it is resolved, after which it renders the component's `children` as a function with the resolved data.\n\nIf the promise is rejected, the `Await` component will throw the serialized error, which can be caught by the nearest error boundary.\n\n[//]: # 'DeferredWithAwaitFinalTip'\n\n> [!TIP]\n> In React 19, you can use the `use()` hook instead of `Await`\n\n[//]: # 'DeferredWithAwaitFinalTip'\n\n## Deferred Data Loading with External libraries\n\nWhen your strategy for fetching information for the route relies on [External Data Loading](./external-data-loading.md) with an external library like [TanStack Query](https://tanstack.com/query), deferred data loading works a bit differently, as the library handles the data fetching and caching for you outside of TanStack Router.\n\nSo, instead of using `defer` and `Await`, you'll instead want to use the Route's `loader` to kick off the data fetching and then use the library's hooks to access the data in your components.\n\n```tsx\n// src/routes/posts.$postId.tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { slowDataOptions, fastDataOptions } from '~/api/query-options'\n\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ context: { queryClient } }) => {\n // Kick off the fetching of some slower data, but do not await it\n queryClient.prefetchQuery(slowDataOptions())\n\n // Fetch and await some data that resolves quickly\n await queryClient.ensureQueryData(fastDataOptions())\n },\n})\n```\n\nThen in your component, you can use the library's hooks to access the data:\n\n```tsx\n// src/routes/posts.$postId.tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { useSuspenseQuery } from '@tanstack/react-query'\nimport { slowDataOptions, fastDataOptions } from '~/api/query-options'\n\nexport const Route = createFileRoute('/posts/$postId')({\n // ...\n component: PostIdComponent,\n})\n\nfunction PostIdComponent() {\n const fastData = useSuspenseQuery(fastDataOptions())\n\n // do something with fastData\n\n return (\n <Suspense fallback={<div>Loading...</div>}>\n <SlowDataComponent />\n </Suspense>\n )\n}\n\nfunction SlowDataComponent() {\n const data = useSuspenseQuery(slowDataOptions())\n\n return <div>{data}</div>\n}\n```\n\n## Caching and Invalidation\n\nStreamed promises follow the same lifecycle as the loader data they are associated with. They can even be preloaded!\n\n[//]: # 'SSRContent'\n\n## SSR & Streaming Deferred Data\n\n**Streaming requires a server that supports it and for TanStack Router to be configured to use it properly.**\n\nPlease read the entire [Streaming SSR Guide](./ssr.md#streaming-ssr) for step by step instructions on how to set up your server for streaming.\n\n## SSR Streaming Lifecycle\n\nThe following is a high-level overview of how deferred data streaming works with TanStack Router:\n\n- Server\n - Promises are marked and tracked as they are returned from route loaders\n - All loaders resolve and any deferred promises are serialized and embedded into the html\n - The route begins to render\n - Deferred promises rendered with the `<Await>` component trigger suspense boundaries, allowing the server to stream html up to that point\n- Client\n - The client receives the initial html from the server\n - `<Await>` components suspend with placeholder promises while they wait for their data to resolve on the server\n- Server\n - As deferred promises resolve, their results (or errors) are serialized and streamed to the client via an inline script tag\n - The resolved `<Await>` components and their suspense boundaries are resolved and their resulting HTML is streamed to the client along with their dehydrated data\n- Client\n - The suspended placeholder promises within `<Await>` are resolved with the streamed data/error responses and either render the result or throw the error to the nearest error boundary\n\n[//]: # 'SSRContent'\n\n# Document Head Management\n\nDocument head management is the process of managing the head, title, meta, link, and script tags of a document and TanStack Router provides a robust way to manage the document head for full-stack applications that use Start and for single-page applications that use `@tanstack/react-router`. It provides:\n\n- Automatic deduping of `title` and `meta` tags\n- Automatic loading/unloading of tags based on route visibility\n- A composable way to merge `title` and `meta` tags from nested routes\n\nFor full-stack applications that use Start, and even for single-page applications that use `@tanstack/react-router`, managing the document head is a crucial part of any application for the following reasons:\n\n- SEO\n- Social media sharing\n- Analytics\n- CSS and JS loading/unloading\n\nTo manage the document head, it's required that you render both the `<HeadContent />` and `<Scripts />` components and use the `routeOptions.head` property to manage the head of a route, which returns an object with `title`, `meta`, `links`, `styles`, and `scripts` properties.\n\n## Managing the Document Head\n\n```tsx\nexport const Route = createRootRoute({\n head: () => ({\n meta: [\n {\n name: 'description',\n content: 'My App is a web application',\n },\n {\n title: 'My App',\n },\n ],\n links: [\n {\n rel: 'icon',\n href: '/favicon.ico',\n },\n ],\n styles: [\n {\n media: 'all and (max-width: 500px)',\n children: `p {\n color: blue;\n background-color: yellow;\n }`,\n },\n ],\n scripts: [\n {\n src: 'https://www.google-analytics.com/analytics.js',\n },\n ],\n }),\n})\n```\n\n### Deduping\n\nOut of the box, TanStack Router will dedupe `title` and `meta` tags, preferring the **last** occurrence of each tag found in nested routes.\n\n- `title` tags defined in nested routes will override a `title` tag defined in a parent route (but you can compose them together, which is covered in a future section of this guide)\n- `meta` tags with the same `name` or `property` will be overridden by the last occurrence of that tag found in nested routes\n\n### `<HeadContent />`\n\nThe `<HeadContent />` component is **required** to render the head, title, meta, link, and head-related script tags of a document.\n\nIt should be **rendered either in the `<head>` tag of your root layout or as high up in the component tree as possible** if your application doesn't or can't manage the `<head>` tag.\n\n### Start/Full-Stack Applications\n\n```tsx\nimport { HeadContent } from '@tanstack/react-router'\n\nexport const Route = createRootRoute({\n component: () => (\n <html>\n <head>\n <HeadContent />\n </head>\n <body>\n <Outlet />\n </body>\n </html>\n ),\n})\n```\n\n### Single-Page Applications\n\nFirst, remove the `<title>` tag from the the index.html if you have set any.\n\n```tsx\nimport { HeadContent } from '@tanstack/react-router'\n\nconst rootRoute = createRootRoute({\n component: () => (\n <>\n <HeadContent />\n <Outlet />\n </>\n ),\n})\n```\n\n## Managing Body Scripts\n\nIn addition to scripts that can be rendered in the `<head>` tag, you can also render scripts in the `<body>` tag using the `routeOptions.scripts` property. This is useful for loading scripts (even inline scripts) that require the DOM to be loaded, but before the main entry point of your application (which includes hydration if you're using Start or a full-stack implementation of TanStack Router).\n\nTo do this, you must:\n\n- Use the `scripts` property of the `routeOptions` object\n- [Render the `<Scripts />` component](#scripts)\n\n```tsx\nexport const Route = createRootRoute({\n scripts: () => [\n {\n children: 'console.log(\"Hello, world!\")',\n },\n ],\n})\n```\n\n### `<Scripts />`\n\nThe `<Scripts />` component is **required** to render the body scripts of a document. It should be rendered either in the `<body>` tag of your root layout or as high up in the component tree as possible if your application doesn't or can't manage the `<body>` tag.\n\n### Example\n\n```tsx\nimport { createFileRoute, Scripts } from '@tanstack/react-router'\nexport const Router = createFileRoute('/')({\n component: () => (\n <html>\n <head />\n <body>\n <Outlet />\n <Scripts />\n </body>\n </html>\n ),\n})\n```\n\n```tsx\nimport { Scripts, createRootRoute } from '@tanstack/react-router'\n\nexport const Route = createRootRoute({\n component: () => (\n <>\n <Outlet />\n <Scripts />\n </>\n ),\n})\n```\n\n# External Data Loading\n\n> [!IMPORTANT]\n> This guide is geared towards external state management libraries and their integration with TanStack Router for data fetching, ssr, hydration/dehydration and streaming. If you haven't read the standard [Data Loading](./data-loading.md) guide, please do so first.\n\n## To **Store** or to **Coordinate**?\n\nWhile Router is very capable of storing and managing most data needs out of the box, sometimes you just might want something more robust!\n\nRouter is designed to be a perfect **coordinator** for external data fetching and caching libraries. This means that you can use any data fetching/caching library you want, and the router will coordinate the loading of your data in a way that aligns with your users' navigation and expectations of freshness.\n\n## What data fetching libraries are supported?\n\nAny data fetching library that supports asynchronous promises can be used with TanStack Router. This includes:\n\n- [TanStack Query](https://tanstack.com/query/latest/docs/react/overview)\n- [SWR](https://swr.vercel.app/)\n- [RTK Query](https://redux-toolkit.js.org/rtk-query/overview)\n- [urql](https://formidable.com/open-source/urql/)\n- [Relay](https://relay.dev/)\n- [Apollo](https://www.apollographql.com/docs/react/)\n\nOr, even...\n\n- [Zustand](https://zustand-demo.pmnd.rs/)\n- [Jotai](https://jotai.org/)\n- [Recoil](https://recoiljs.org/)\n- [Redux](https://redux.js.org/)\n\nLiterally any library that **can return a promise and read/write data** can be integrated.\n\n## Using Loaders to ensure data is loaded\n\nThe easiest way to integrate external caching/data library into Router is to use `route.loader`s to ensure that the data required inside of a route has been loaded and is ready to be displayed.\n\n> \u26A0\uFE0F BUT WHY? It's very important to preload your critical render data in the loader for a few reasons:\n>\n> - No \"flash of loading\" states\n> - No waterfall data fetching, caused by component based fetching\n> - Better for SEO. If your data is available at render time, it will be indexed by search engines.\n\nHere is a naive illustration (don't do this) of using a Route's `loader` option to seed the cache for some data:\n\n```tsx\n// src/routes/posts.tsx\nlet postsCache = []\n\nexport const Route = createFileRoute('/posts')({\n loader: async () => {\n postsCache = await fetchPosts()\n },\n component: () => {\n return (\n <div>\n {postsCache.map((post) => (\n <Post key={post.id} post={post} />\n ))}\n </div>\n )\n },\n})\n```\n\nThis example is **obviously flawed**, but illustrates the point that you can use a route's `loader` option to seed your cache with data. Let's take a look at a more realistic example using TanStack Query.\n\n- Replace `fetchPosts` with your preferred data fetching library's prefetching API\n- Replace `postsCache` with your preferred data fetching library's read-or-fetch API or hook\n\n## A more realistic example using TanStack Query\n\nLet's take a look at a more realistic example using TanStack Query.\n\n```tsx\n// src/routes/posts.tsx\nconst postsQueryOptions = queryOptions({\n queryKey: ['posts'],\n queryFn: () => fetchPosts(),\n})\n\nexport const Route = createFileRoute('/posts')({\n // Use the `loader` option to ensure that the data is loaded\n loader: () => queryClient.ensureQueryData(postsQueryOptions),\n component: () => {\n // Read the data from the cache and subscribe to updates\n const {\n data: { posts },\n } = useSuspenseQuery(postsQueryOptions)\n\n return (\n <div>\n {posts.map((post) => (\n <Post key={post.id} post={post} />\n ))}\n </div>\n )\n },\n})\n```\n\n### Error handling with TanStack Query\n\nWhen an error occurs while using `suspense` with `TanStack Query`, you need to let queries know that you want to try again when re-rendering. This can be done by using the `reset` function provided by the `useQueryErrorResetBoundary` hook. You can invoke this function in an effect as soon as the error component mounts. This will make sure that the query is reset and will try to fetch data again when the route component is rendered again. This will also cover cases where users navigate away from the route instead of clicking the `retry` button.\n\n```tsx\nexport const Route = createFileRoute('/')({\n loader: () => queryClient.ensureQueryData(postsQueryOptions),\n errorComponent: ({ error, reset }) => {\n const router = useRouter()\n const queryErrorResetBoundary = useQueryErrorResetBoundary()\n\n useEffect(() => {\n // Reset the query error boundary\n queryErrorResetBoundary.reset()\n }, [queryErrorResetBoundary])\n\n return (\n <div>\n {error.message}\n <button\n onClick={() => {\n // Invalidate the route to reload the loader, and reset any router error boundaries\n router.invalidate()\n }}\n >\n retry\n </button>\n </div>\n )\n },\n})\n```\n\n## SSR Dehydration/Hydration\n\nTools that are able can integrate with TanStack Router's convenient Dehydration/Hydration APIs to shuttle dehydrated data between the server and client and rehydrate it where needed. Let's go over how to do this with both 3rd party critical data and 3rd party deferred data.\n\n## Critical Dehydration/Hydration\n\n**For critical data needed for the first render/paint**, TanStack Router supports **`dehydrate` and `hydrate`** options when configuring the `Router`. These callbacks are functions that are automatically called on the server and client when the router dehydrates and hydrates normally and allow you to augment the dehydrated data with your own data.\n\nThe `dehydrate` function can return any serializable JSON data which will get merged and injected into the dehydrated payload that is sent to the client.\n\nFor example, let's dehydrate and hydrate a TanStack Query `QueryClient` so that our data we fetched on the server will be available for hydration on the client.\n\n```tsx\n// src/router.tsx\n\nexport function createRouter() {\n // Make sure you create your loader client or similar data\n // stores inside of your `createRouter` function. This ensures\n // that your data stores are unique to each request and\n // always present on both server and client.\n const queryClient = new QueryClient()\n\n return createRouter({\n routeTree,\n // Optionally provide your loaderClient to the router context for\n // convenience (you can provide anything you want to the router\n // context!)\n context: {\n queryClient,\n },\n // On the server, dehydrate the loader client so the router\n // can serialize it and send it to the client for us\n dehydrate: () => {\n return {\n queryClientState: dehydrate(queryClient),\n }\n },\n // On the client, hydrate the loader client with the data\n // we dehydrated on the server\n hydrate: (dehydrated) => {\n hydrate(queryClient, dehydrated.queryClientState)\n },\n // Optionally, we can use `Wrap` to wrap our router in the loader client provider\n Wrap: ({ children }) => {\n return (\n <QueryClientProvider client={queryClient}>\n {children}\n </QueryClientProvider>\n )\n },\n })\n}\n```\n\n# History Types\n\nWhile it's not required to know the `@tanstack/history` API itself to use TanStack Router, it's a good idea to understand how it works. Under the hood, TanStack Router requires and uses a `history` abstraction to manage the routing history.\n\nIf you don't create a history instance, a browser-oriented instance of this API is created for you when the router is initialized. If you need a special history API type, You can use the `@tanstack/history` package to create your own:\n\n- `createBrowserHistory`: The default history type.\n- `createHashHistory`: A history type that uses a hash to track history.\n- `createMemoryHistory`: A history type that keeps the history in memory.\n\nOnce you have a history instance, you can pass it to the `Router` constructor:\n\n```ts\nimport { createMemoryHistory, createRouter } from '@tanstack/react-router'\n\nconst memoryHistory = createMemoryHistory({\n initialEntries: ['/'], // Pass your initial url\n})\n\nconst router = createRouter({ routeTree, history: memoryHistory })\n```\n\n## Browser Routing\n\nThe `createBrowserHistory` is the default history type. It uses the browser's history API to manage the browser history.\n\n## Hash Routing\n\nHash routing can be helpful if your server doesn't support rewrites to index.html for HTTP requests (among other environments that don't have a server).\n\n```ts\nimport { createHashHistory, createRouter } from '@tanstack/react-router'\n\nconst hashHistory = createHashHistory()\n\nconst router = createRouter({ routeTree, history: hashHistory })\n```\n\n## Memory Routing\n\nMemory routing is useful in environments that are not a browser or when you do not want components to interact with the URL.\n\n```ts\nimport { createMemoryHistory, createRouter } from '@tanstack/react-router'\n\nconst memoryHistory = createMemoryHistory({\n initialEntries: ['/'], // Pass your initial url\n})\n\nconst router = createRouter({ routeTree, history: memoryHistory })\n```\n\nRefer to the [SSR Guide](./ssr.md#server-history) for usage on the server for server-side rendering.\n\n# Link Options\n\nYou may want to reuse options that are intended to be passed to `Link`, `redirect` or `navigate`. In which case you may decide an object literal is a good way to represent options passed to `Link`.\n\n```tsx\nconst dashboardLinkOptions = {\n to: '/dashboard',\n search: { search: '' },\n}\n\nfunction DashboardComponent() {\n return <Link {...dashboardLinkOptions} />\n}\n```\n\nThere are a few problems here. `dashboardLinkOptions.to` is inferred as `string` which by default will resolve to every route when passed to `Link`, `navigate` or `redirect` (this particular issue could be fixed by `as const`). The other issue here is we do not know `dashboardLinkOptions` even passes the type checker until it is spread into `Link`. We could very easily create incorrect navigation options and only when the options are spread into `Link` do we know there is a type error.\n\n### Using `linkOptions` function to create re-usable options\n\n`linkOptions` is a function which type checks an object literal and returns the inferred input as is. This provides type safety on options exactly like `Link` before it is used allowing for easier maintenance and re-usability. Our above example using `linkOptions` looks like this:\n\n```tsx\nconst dashboardLinkOptions = linkOptions({\n to: '/dashboard',\n search: { search: '' },\n})\n\nfunction DashboardComponent() {\n return <Link {...dashboardLinkOptions} />\n}\n```\n\nThis allows eager type checking of `dashboardLinkOptions` which can then be re-used anywhere\n\n```tsx\nconst dashboardLinkOptions = linkOptions({\n to: '/dashboard',\n search: { search: '' },\n})\n\nexport const Route = createFileRoute('/dashboard')({\n component: DashboardComponent,\n validateSearch: (input) => ({ search: input.search }),\n beforeLoad: () => {\n // can used in redirect\n throw redirect(dashboardLinkOptions)\n },\n})\n\nfunction DashboardComponent() {\n const navigate = useNavigate()\n\n return (\n <div>\n {/** can be used in navigate */}\n <button onClick={() => navigate(dashboardLinkOptions)} />\n\n {/** can be used in Link */}\n <Link {...dashboardLinkOptions} />\n </div>\n )\n}\n```\n\n### An array of `linkOptions`\n\nWhen creating navigation you might loop over an array to construct a navigation bar. In which case `linkOptions` can be used to type check an array of object literals which are intended for `Link` props\n\n```tsx\nconst options = linkOptions([\n {\n to: '/dashboard',\n label: 'Summary',\n activeOptions: { exact: true },\n },\n {\n to: '/dashboard/invoices',\n label: 'Invoices',\n },\n {\n to: '/dashboard/users',\n label: 'Users',\n },\n])\n\nfunction DashboardComponent() {\n return (\n <>\n <div className=\"flex items-center border-b\">\n <h2 className=\"text-xl p-2\">Dashboard</h2>\n </div>\n\n <div className=\"flex flex-wrap divide-x\">\n {options.map((option) => {\n return (\n <Link\n {...option}\n key={option.to}\n activeProps={{ className: `font-bold` }}\n className=\"p-2\"\n >\n {option.label}\n </Link>\n )\n })}\n </div>\n <hr />\n\n <Outlet />\n </>\n )\n}\n```\n\nThe input of `linkOptions` is inferred and returned, as shown with the use of `label` as this does not exist on `Link` props\n\n# Navigation Blocking\n\nNavigation blocking is a way to prevent navigation from happening. This is typical if a user attempts to navigate while they:\n\n- Have unsaved changes\n- Are in the middle of a form\n- Are in the middle of a payment\n\nIn these situations, a prompt or custom UI should be shown to the user to confirm they want to navigate away.\n\n- If the user confirms, navigation will continue as normal\n- If the user cancels, all pending navigations will be blocked\n\n## How does navigation blocking work?\n\nNavigation blocking adds one or more layers of \"blockers\" to the entire underlying history API. If any blockers are present, navigation will be paused via one of the following ways:\n\n- Custom UI\n - If the navigation is triggered by something we control at the router level, we can allow you to perform any task or show any UI you'd like to the user to confirm the action. Each blocker's `blocker` function will be asynchronously and sequentially executed. If any blocker function resolves or returns `true`, the navigation will be allowed and all other blockers will continue to do the same until all blockers have been allowed to proceed. If any single blocker resolves or returns `false`, the navigation will be canceled and the rest of the `blocker` functions will be ignored.\n- The `onbeforeunload` event\n - For page events that we cannot control directly, we rely on the browser's `onbeforeunload` event. If the user attempts to close the tab or window, refresh, or \"unload\" the page assets in any way, the browser's generic \"Are you sure you want to leave?\" dialog will be shown. If the user confirms, all blockers will be bypassed and the page will unload. If the user cancels, the unload will be cancelled, and the page will remain as is.\n\n## How do I use navigation blocking?\n\nThere are 2 ways to use navigation blocking:\n\n- Hook/logical-based blocking\n- Component-based blocking\n\n## Hook/logical-based blocking\n\nLet's imagine we want to prevent navigation if a form is dirty. We can do this by using the `useBlocker` hook:\n\n[//]: # 'HookBasedBlockingExample'\n\n```tsx\nimport { useBlocker } from '@tanstack/react-router'\n\nfunction MyComponent() {\n const [formIsDirty, setFormIsDirty] = useState(false)\n\n useBlocker({\n shouldBlockFn: () => {\n if (!formIsDirty) return false\n\n const shouldLeave = confirm('Are you sure you want to leave?')\n return !shouldLeave\n },\n })\n\n // ...\n}\n```\n\n[//]: # 'HookBasedBlockingExample'\n\n`shouldBlockFn` gives you type safe access to the `current` and `next` location:\n\n```tsx\nimport { useBlocker } from '@tanstack/react-router'\n\nfunction MyComponent() {\n // always block going from /foo to /bar/123?hello=world\n const { proceed, reset, status } = useBlocker({\n shouldBlockFn: ({ current, next }) => {\n return (\n current.routeId === '/foo' &&\n next.fullPath === '/bar/$id' &&\n next.params.id === 123 &&\n next.search.hello === 'world'\n )\n },\n withResolver: true,\n })\n\n // ...\n}\n```\n\nNote that even if `shouldBlockFn` returns `false`, the browser's `beforeunload` event may still be triggered on page reloads or tab closing. To gain control over this, you can use the `enableBeforeUnload` option to conditionally register the `beforeunload` handler:\n\n[//]: # 'HookBasedBlockingExample'\n\n```tsx\nimport { useBlocker } from '@tanstack/react-router'\n\nfunction MyComponent() {\n const [formIsDirty, setFormIsDirty] = useState(false)\n\n useBlocker({\n {/* ... */}\n enableBeforeUnload: formIsDirty, // or () => formIsDirty\n })\n\n // ...\n}\n```\n\nYou can find more information about the `useBlocker` hook in the [API reference](../api/router/useBlockerHook.md).\n\n## Component-based blocking\n\nIn addition to logical/hook based blocking, you can use the `Block` component to achieve similar results:\n\n[//]: # 'ComponentBasedBlockingExample'\n\n```tsx\nimport { Block } from '@tanstack/react-router'\n\nfunction MyComponent() {\n const [formIsDirty, setFormIsDirty] = useState(false)\n\n return (\n <Block\n shouldBlockFn={() => {\n if (!formIsDirty) return false\n\n const shouldLeave = confirm('Are you sure you want to leave?')\n return !shouldLeave\n }}\n enableBeforeUnload={formIsDirty}\n />\n )\n\n // OR\n\n return (\n <Block\n shouldBlockFn={() => formIsDirty}\n enableBeforeUnload={formIsDirty}\n withResolver\n >\n {({ status, proceed, reset }) => <>{/* ... */}</>}\n </Block>\n )\n}\n```\n\n[//]: # 'ComponentBasedBlockingExample'\n\n## How can I show a custom UI?\n\nIn most cases, using `window.confirm` in the `shouldBlockFn` function with `withResolver: false` in the hook is enough since it will clearly show the user that the navigation is being blocked and resolve the blocking based on their response.\n\nHowever, in some situations, you might want to show a custom UI that is intentionally less disruptive and more integrated with your app's design.\n\n**Note:** The return value of `shouldBlockFn` does not resolve the blocking if `withResolver` is `true`.\n\n### Hook/logical-based custom UI with resolver\n\n[//]: # 'HookBasedCustomUIBlockingWithResolverExample'\n\n```tsx\nimport { useBlocker } from '@tanstack/react-router'\n\nfunction MyComponent() {\n const [formIsDirty, setFormIsDirty] = useState(false)\n\n const { proceed, reset, status } = useBlocker({\n shouldBlockFn: () => formIsDirty,\n withResolver: true,\n })\n\n // ...\n\n return (\n <>\n {/* ... */}\n {status === 'blocked' && (\n <div>\n <p>Are you sure you want to leave?</p>\n <button onClick={proceed}>Yes</button>\n <button onClick={reset}>No</button>\n </div>\n )}\n </>\n}\n```\n\n[//]: # 'HookBasedCustomUIBlockingWithResolverExample'\n\n### Hook/logical-based custom UI without resolver\n\n[//]: # 'HookBasedCustomUIBlockingWithoutResolverExample'\n\n```tsx\nimport { useBlocker } from '@tanstack/react-router'\n\nfunction MyComponent() {\n const [formIsDirty, setFormIsDirty] = useState(false)\n\n useBlocker({\n shouldBlockFn: () => {\n if (!formIsDirty) {\n return false\n }\n\n const shouldBlock = new Promise<boolean>((resolve) => {\n // Using a modal manager of your choice\n modals.open({\n title: 'Are you sure you want to leave?',\n children: (\n <SaveBlocker\n confirm={() => {\n modals.closeAll()\n resolve(false)\n }}\n reject={() => {\n modals.closeAll()\n resolve(true)\n }}\n />\n ),\n onClose: () => resolve(true),\n })\n })\n return shouldBlock\n },\n })\n\n // ...\n}\n```\n\n[//]: # 'HookBasedCustomUIBlockingWithoutResolverExample'\n\n### Component-based custom UI\n\nSimilarly to the hook, the `Block` component returns the same state and functions as render props:\n\n[//]: # 'ComponentBasedCustomUIBlockingExample'\n\n```tsx\nimport { Block } from '@tanstack/react-router'\n\nfunction MyComponent() {\n const [formIsDirty, setFormIsDirty] = useState(false)\n\n return (\n <Block shouldBlockFn={() => formIsDirty} withResolver>\n {({ status, proceed, reset }) => (\n <>\n {/* ... */}\n {status === 'blocked' && (\n <div>\n <p>Are you sure you want to leave?</p>\n <button onClick={proceed}>Yes</button>\n <button onClick={reset}>No</button>\n </div>\n )}\n </>\n )}\n </Block>\n )\n}\n```\n\n[//]: # 'ComponentBasedCustomUIBlockingExample'\n\n# Navigation\n\n## Everything is Relative\n\nBelieve it or not, every navigation within an app is **relative**, even if you aren't using explicit relative path syntax (`../../somewhere`). Any time a link is clicked or an imperative navigation call is made, you will always have an **origin** path and a **destination** path which means you are navigating **from** one route **to** another route.\n\nTanStack Router keeps this constant concept of relative navigation in mind for every navigation, so you'll constantly see two properties in the API:\n\n- `from` - The origin route path\n- `to` - The destination route path\n\n> \u26A0\uFE0F If a `from` route path isn't provided the router will assume you are navigating from the root `/` route and only auto-complete absolute paths. After all, you need to know where you are from in order to know where you're going \uD83D\uDE09.\n\n## Shared Navigation API\n\nEvery navigation and route matching API in TanStack Router uses the same core interface with minor differences depending on the API. This means that you can learn navigation and route matching once and use the same syntax and concepts across the library.\n\n### `ToOptions` Interface\n\nThis is the core `ToOptions` interface that is used in every navigation and route matching API:\n\n```ts\ntype ToOptions<\n TRouteTree extends AnyRoute = AnyRoute,\n TFrom extends RoutePaths<TRouteTree> | string = string,\n TTo extends string = '',\n> = {\n // `from` is an optional route ID or path. If it is not supplied, only absolute paths will be auto-completed and type-safe. It's common to supply the route.fullPath of the origin route you are rendering from for convenience. If you don't know the origin route, leave this empty and work with absolute paths or unsafe relative paths.\n from?: string\n // `to` can be an absolute route path or a relative path from the `from` option to a valid route path. \u26A0\uFE0F Do not interpolate path params, hash or search params into the `to` options. Use the `params`, `search`, and `hash` options instead.\n to: string\n // `params` is either an object of path params to interpolate into the `to` option or a function that supplies the previous params and allows you to return new ones. This is the only way to interpolate dynamic parameters into the final URL. Depending on the `from` and `to` route, you may need to supply none, some or all of the path params. TypeScript will notify you of the required params if there are any.\n params:\n | Record<string, unknown>\n | ((prevParams: Record<string, unknown>) => Record<string, unknown>)\n // `search` is either an object of query params or a function that supplies the previous search and allows you to return new ones. Depending on the `from` and `to` route, you may need to supply none, some or all of the query params. TypeScript will notify you of the required search params if there are any.\n search:\n | Record<string, unknown>\n | ((prevSearch: Record<string, unknown>) => Record<string, unknown>)\n // `hash` is either a string or a function that supplies the previous hash and allows you to return a new one.\n hash?: string | ((prevHash: string) => string)\n // `state` is either an object of state or a function that supplies the previous state and allows you to return a new one. State is stored in the history API and can be useful for passing data between routes that you do not want to permanently store in URL search params.\n state?:\n | Record<string, any>\n | ((prevState: Record<string, unknown>) => Record<string, unknown>)\n}\n```\n\n> \uD83E\uDDE0 Every route object has a `to` property, which can be used as the `to` for any navigation or route matching API. Where possible, this will allow you to avoid plain strings and use type-safe route references instead:\n\n```tsx\nimport { Route as aboutRoute } from './routes/about.tsx'\n\nfunction Comp() {\n return <Link to={aboutRoute.to}>About</Link>\n}\n```\n\n### `NavigateOptions` Interface\n\nThis is the core `NavigateOptions` interface that extends `ToOptions`. Any API that is actually performing a navigation will use this interface:\n\n```ts\nexport type NavigateOptions<\n TRouteTree extends AnyRoute = AnyRoute,\n TFrom extends RoutePaths<TRouteTree> | string = string,\n TTo extends string = '',\n> = ToOptions<TRouteTree, TFrom, TTo> & {\n // `replace` is a boolean that determines whether the navigation should replace the current history entry or push a new one.\n replace?: boolean\n // `resetScroll` is a boolean that determines whether scroll position will be reset to 0,0 after the location is committed to browser history.\n resetScroll?: boolean\n // `hashScrollIntoView` is a boolean or object that determines whether an id matching the hash will be scrolled into view after the location is committed to history.\n hashScrollIntoView?: boolean | ScrollIntoViewOptions\n // `viewTransition` is either a boolean or function that determines if and how the browser will call document.startViewTransition() when navigating.\n viewTransition?: boolean | ViewTransitionOptions\n // `ignoreBlocker` is a boolean that determines if navigation should ignore any blockers that might prevent it.\n ignoreBlocker?: boolean\n // `reloadDocument` is a boolean that determines if navigation to a route inside of router will trigger a full page load instead of the traditional SPA navigation.\n reloadDocument?: boolean\n // `href` is a string that can be used in place of `to` to navigate to a full built href, e.g. pointing to an external target.\n href?: string\n}\n```\n\n### `LinkOptions` Interface\n\nAnywhere an actual `<a>` tag the `LinkOptions` interface which extends `NavigateOptions` will be available:\n\n```tsx\nexport type LinkOptions<\n TRouteTree extends AnyRoute = AnyRoute,\n TFrom extends RoutePaths<TRouteTree> | string = string,\n TTo extends string = '',\n> = NavigateOptions<TRouteTree, TFrom, TTo> & {\n // The standard anchor tag target attribute\n target?: HTMLAnchorElement['target']\n // Defaults to `{ exact: false, includeHash: false }`\n activeOptions?: {\n exact?: boolean\n includeHash?: boolean\n includeSearch?: boolean\n explicitUndefined?: boolean\n }\n // If set, will preload the linked route on hover and cache it for this many milliseconds in hopes that the user will eventually navigate there.\n preload?: false | 'intent'\n // Delay intent preloading by this many milliseconds. If the intent exits before this delay, the preload will be cancelled.\n preloadDelay?: number\n // If true, will render the link without the href attribute\n disabled?: boolean\n}\n```\n\n## Navigation API\n\nWith relative navigation and all of the interfaces in mind now, let's talk about the different flavors of navigation API at your disposal:\n\n- The `<Link>` component\n - Generates an actual `<a>` tag with a valid `href` which can be click or even cmd/ctrl + clicked to open in a new tab\n- The `useNavigate()` hook\n - When possible, `Link` component should be used for navigation, but sometimes you need to navigate imperatively as a result of a side-effect. `useNavigate` returns a function that can be called to perform an immediate client-side navigation.\n- The `<Navigate>` component\n - Renders nothing and performs an immediate client-side navigation.\n- The `Router.navigate()` method\n - This is the most powerful navigation API in TanStack Router. Similar to `useNavigate`, it imperatively navigates, but is available everywhere you have access to your router.\n\n\u26A0\uFE0F None of these APIs are a replacement for server-side redirects. If you need to redirect a user immediately from one route to another before mounting your application, use a server-side redirect instead of a client-side navigation.\n\n## `<Link>` Component\n\nThe `Link` component is the most common way to navigate within an app. It renders an actual `<a>` tag with a valid `href` attribute which can be clicked or even cmd/ctrl + clicked to open in a new tab. It also supports any normal `<a>` attributes including `target` to open links in new windows, etc.\n\nIn addition to the [`LinkOptions`](#linkoptions-interface) interface, the `Link` component also supports the following props:\n\n```tsx\nexport type LinkProps<\n TFrom extends RoutePaths<RegisteredRouter['routeTree']> | string = string,\n TTo extends string = '',\n> = LinkOptions<RegisteredRouter['routeTree'], TFrom, TTo> & {\n // A function that returns additional props for the `active` state of this link. These props override other props passed to the link (`style`'s are merged, `className`'s are concatenated)\n activeProps?:\n | FrameworkHTMLAnchorTagAttributes\n | (() => FrameworkHTMLAnchorAttributes)\n // A function that returns additional props for the `inactive` state of this link. These props override other props passed to the link (`style`'s are merged, `className`'s are concatenated)\n inactiveProps?:\n | FrameworkHTMLAnchorAttributes\n | (() => FrameworkHTMLAnchorAttributes)\n}\n```\n\n### Absolute Links\n\nLet's make a simple static link!\n\n```tsx\nimport { Link } from '@tanstack/react-router'\n\nconst link = <Link to=\"/about\">About</Link>\n```\n\n### Dynamic Links\n\nDynamic links are links that have dynamic segments in them. For example, a link to a blog post might look like this:\n\n```tsx\nconst link = (\n <Link\n to=\"/blog/post/$postId\"\n params={{\n postId: 'my-first-blog-post',\n }}\n >\n Blog Post\n </Link>\n)\n```\n\nKeep in mind that normally dynamic segment params are `string` values, but they can also be any other type that you parse them to in your route options. Either way, the type will be checked at compile time to ensure that you are passing the correct type.\n\n### Relative Links\n\nBy default, all links are absolute unless a `from` route path is provided. This means that the above link will always navigate to the `/about` route regardless of what route you are currently on.\n\nRelative links can be combined with a `from` route path. If a from route path isn't provided, relative paths default to the current active location.\n\n> [!NOTE]\n> Keep in mind that when calling useNavigate as a method on the route, for example `Route.useNavigate`, then the `from` location is predefined to be the route it's called on.\n>\n> Another common pitfall is when using this in a pathless layout route, since the pathless layout route does not have an actual path, the `from` location is regarded as the parent of the pathless layout route. Hence relative routing will be resolved from this parent.\n\n```tsx\nconst postIdRoute = createRoute({\n path: '/blog/post/$postId',\n})\n\nconst link = (\n <Link from={postIdRoute.fullPath} to=\"../categories\">\n Categories\n </Link>\n)\n```\n\nAs seen above, it's common to provide the `route.fullPath` as the `from` route path. This is because the `route.fullPath` is a reference that will update if you refactor your application. However, sometimes it's not possible to import the route directly, in which case it's fine to provide the route path directly as a string. It will still get type-checked as per usual!\n\n### Special relative paths: `\".\"` and `\"..\"`\n\nQuite often you might want to reload the current location or another `from` path, for example, to rerun the loaders on the current and/or parent routes, or maybe navigate back to a parent route. This can be achieved by specifying a `to` route path of `\".\"` which will reload the current location or provided `from` path.\n\nAnother common need is to navigate one route back relative to the current location or another path. By specifying a `to` route path of `\"..\"` navigation will be resolved to the first parent route preceding the current location.\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n component: PostComponent,\n})\n\nfunction PostComponent() {\n return (\n <div>\n <Link to=\".\">Reload the current route of /posts/$postId</Link>\n <Link to=\"..\">Navigate back to /posts</Link>\n // the below are all equivalent\n <Link to=\"/posts\">Navigate back to /posts</Link>\n <Link from=\"/posts\" to=\".\">\n Navigate back to /posts\n </Link>\n // the below are all equivalent\n <Link to=\"/\">Navigate to root</Link>\n <Link from=\"/posts\" to=\"..\">\n Navigate to root\n </Link>\n </div>\n )\n}\n```\n\n### Search Param Links\n\nSearch params are a great way to provide additional context to a route. For example, you might want to provide a search query to a search page:\n\n```tsx\nconst link = (\n <Link\n to=\"/search\"\n search={{\n query: 'tanstack',\n }}\n >\n Search\n </Link>\n)\n```\n\nIt's also common to want to update a single search param without supplying any other information about the existing route. For example, you might want to update the page number of a search result:\n\n```tsx\nconst link = (\n <Link\n to=\".\"\n search={(prev) => ({\n ...prev,\n page: prev.page + 1,\n })}\n >\n Next Page\n </Link>\n)\n```\n\n### Search Param Type Safety\n\nSearch params are a highly dynamic state management mechanism, so it's important to ensure that you are passing the correct types to your search params. We'll see in a later section in detail how to validate and ensure search params typesafety, among other great features!\n\n### Hash Links\n\nHash links are a great way to link to a specific section of a page. For example, you might want to link to a specific section of a blog post:\n\n```tsx\nconst link = (\n <Link\n to=\"/blog/post/$postId\"\n params={{\n postId: 'my-first-blog-post',\n }}\n hash=\"section-1\"\n >\n Section 1\n </Link>\n)\n```\n\n### Navigating with Optional Parameters\n\nOptional path parameters provide flexible navigation patterns where you can include or omit parameters as needed. Optional parameters use the `{-$paramName}` syntax and offer fine-grained control over URL structure.\n\n#### Parameter Inheritance vs Removal\n\nWhen navigating with optional parameters, you have two main strategies:\n\n**Inheriting Current Parameters**\nUse `params: {}` to inherit all current route parameters:\n\n```tsx\n// Inherits current route parameters\n<Link to=\"/posts/{-$category}\" params={{}}>\n All Posts\n</Link>\n```\n\n**Removing Parameters** \nSet parameters to `undefined` to explicitly remove them:\n\n```tsx\n// Removes the category parameter\n<Link to=\"/posts/{-$category}\" params={{ category: undefined }}>\n All Posts\n</Link>\n```\n\n#### Basic Optional Parameter Navigation\n\n```tsx\n// Navigate with optional parameter\n<Link\n to=\"/posts/{-$category}\"\n params={{ category: 'tech' }}\n>\n Tech Posts\n</Link>\n\n// Navigate without optional parameter\n<Link\n to=\"/posts/{-$category}\"\n params={{ category: undefined }}\n>\n All Posts\n</Link>\n\n// Navigate using parameter inheritance\n<Link\n to=\"/posts/{-$category}\"\n params={{}}\n>\n Current Category\n</Link>\n```\n\n#### Function-Style Parameter Updates\n\nFunction-style parameter updates are particularly useful with optional parameters:\n\n```tsx\n// Remove a parameter using function syntax\n<Link\n to=\"/posts/{-$category}\"\n params={(prev) => ({ ...prev, category: undefined })}\n>\n Clear Category\n</Link>\n\n// Update a parameter while keeping others\n<Link\n to=\"/articles/{-$category}/{-$slug}\"\n params={(prev) => ({ ...prev, category: 'news' })}\n>\n News Articles\n</Link>\n\n// Conditionally set parameters\n<Link\n to=\"/posts/{-$category}\"\n params={(prev) => ({\n ...prev,\n category: someCondition ? 'tech' : undefined\n })}\n>\n Conditional Category\n</Link>\n```\n\n#### Multiple Optional Parameters\n\nWhen working with multiple optional parameters, you can mix and match which ones to include:\n\n```tsx\n// Navigate with some optional parameters\n<Link\n to=\"/posts/{-$category}/{-$slug}\"\n params={{ category: 'tech', slug: undefined }}\n>\n Tech Posts\n</Link>\n\n// Remove all optional parameters\n<Link\n to=\"/posts/{-$category}/{-$slug}\"\n params={{ category: undefined, slug: undefined }}\n>\n All Posts\n</Link>\n\n// Set multiple parameters\n<Link\n to=\"/posts/{-$category}/{-$slug}\"\n params={{ category: 'tech', slug: 'react-tips' }}\n>\n Specific Post\n</Link>\n```\n\n#### Mixed Required and Optional Parameters\n\nOptional parameters work seamlessly with required parameters:\n\n```tsx\n// Required 'id', optional 'tab'\n<Link\n to=\"/users/$id/{-$tab}\"\n params={{ id: '123', tab: 'settings' }}\n>\n User Settings\n</Link>\n\n// Remove optional parameter while keeping required\n<Link\n to=\"/users/$id/{-$tab}\"\n params={{ id: '123', tab: undefined }}\n>\n User Profile\n</Link>\n\n// Use function style with mixed parameters\n<Link\n to=\"/users/$id/{-$tab}\"\n params={(prev) => ({ ...prev, tab: 'notifications' })}\n>\n User Notifications\n</Link>\n```\n\n#### Advanced Optional Parameter Patterns\n\n**Prefix and Suffix Parameters**\nOptional parameters with prefix/suffix work with navigation:\n\n```tsx\n// Navigate to file with optional name\n<Link\n to=\"/files/prefix{-$name}.txt\"\n params={{ name: 'document' }}\n>\n Document File\n</Link>\n\n// Navigate to file without optional name\n<Link\n to=\"/files/prefix{-$name}.txt\"\n params={{ name: undefined }}\n>\n Default File\n</Link>\n```\n\n**All Optional Parameters**\nRoutes where all parameters are optional:\n\n```tsx\n// Navigate to specific date\n<Link\n to=\"/{-$year}/{-$month}/{-$day}\"\n params={{ year: '2023', month: '12', day: '25' }}\n>\n Christmas 2023\n</Link>\n\n// Navigate to partial date\n<Link\n to=\"/{-$year}/{-$month}/{-$day}\"\n params={{ year: '2023', month: '12', day: undefined }}\n>\n December 2023\n</Link>\n\n// Navigate to root with all parameters removed\n<Link\n to=\"/{-$year}/{-$month}/{-$day}\"\n params={{ year: undefined, month: undefined, day: undefined }}\n>\n Home\n</Link>\n```\n\n#### Navigation with Search Params and Optional Parameters\n\nOptional parameters work great in combination with search params:\n\n```tsx\n// Combine optional path params with search params\n<Link\n to=\"/posts/{-$category}\"\n params={{ category: 'tech' }}\n search={{ page: 1, sort: 'newest' }}\n>\n Tech Posts - Page 1\n</Link>\n\n// Remove path param but keep search params\n<Link\n to=\"/posts/{-$category}\"\n params={{ category: undefined }}\n search={(prev) => prev}\n>\n All Posts - Same Filters\n</Link>\n```\n\n#### Imperative Navigation with Optional Parameters\n\nAll the same patterns work with imperative navigation:\n\n```tsx\nfunction Component() {\n const navigate = useNavigate()\n\n const clearFilters = () => {\n navigate({\n to: '/posts/{-$category}/{-$tag}',\n params: { category: undefined, tag: undefined },\n })\n }\n\n const setCategory = (category: string) => {\n navigate({\n to: '/posts/{-$category}/{-$tag}',\n params: (prev) => ({ ...prev, category }),\n })\n }\n\n const applyFilters = (category?: string, tag?: string) => {\n navigate({\n to: '/posts/{-$category}/{-$tag}',\n params: { category, tag },\n })\n }\n}\n```\n\n### Active & Inactive Props\n\nThe `Link` component supports two additional props: `activeProps` and `inactiveProps`. These props are functions that return additional props for the `active` and `inactive` states of the link. All props other than styles and classes passed here will override the original props passed to `Link`. Any styles or classes passed are merged together.\n\nHere's an example:\n\n```tsx\nconst link = (\n <Link\n to=\"/blog/post/$postId\"\n params={{\n postId: 'my-first-blog-post',\n }}\n activeProps={{\n style: {\n fontWeight: 'bold',\n },\n }}\n >\n Section 1\n </Link>\n)\n```\n\n### The `data-status` attribute\n\nIn addition to the `activeProps` and `inactiveProps` props, the `Link` component also adds a `data-status` attribute to the rendered element when it is in an active state. This attribute will be `active` or `undefined` depending on the current state of the link. This can come in handy if you prefer to use data-attributes to style your links instead of props.\n\n### Active Options\n\nThe `Link` component comes with an `activeOptions` property that offers a few options of determining if a link is active or not. The following interface describes those options:\n\n```tsx\nexport interface ActiveOptions {\n // If true, the link will be active if the current route matches the `to` route path exactly (no children routes)\n // Defaults to `false`\n exact?: boolean\n // If true, the link will only be active if the current URL hash matches the `hash` prop\n // Defaults to `false`\n includeHash?: boolean // Defaults to false\n // If true, the link will only be active if the current URL search params inclusively match the `search` prop\n // Defaults to `true`\n includeSearch?: boolean\n // This modifies the `includeSearch` behavior.\n // If true, properties in `search` that are explicitly `undefined` must NOT be present in the current URL search params for the link to be active.\n // defaults to `false`\n explicitUndefined?: boolean\n}\n```\n\nBy default, it will check if the resulting **pathname** is a prefix of the current route. If any search params are provided, it will check that they _inclusively_ match those in the current location. Hashes are not checked by default.\n\nFor example, if you are on the `/blog/post/my-first-blog-post` route, the following links will be active:\n\n```tsx\nconst link1 = (\n <Link to=\"/blog/post/$postId\" params={{ postId: 'my-first-blog-post' }}>\n Blog Post\n </Link>\n)\nconst link2 = <Link to=\"/blog/post\">Blog Post</Link>\nconst link3 = <Link to=\"/blog\">Blog Post</Link>\n```\n\nHowever, the following links will not be active:\n\n```tsx\nconst link4 = (\n <Link to=\"/blog/post/$postId\" params={{ postId: 'my-second-blog-post' }}>\n Blog Post\n </Link>\n)\n```\n\nIt's common for some links to only be active if they are an exact match. A good example of this would be a link to the home page. In scenarios like these, you can pass the `exact: true` option:\n\n```tsx\nconst link = (\n <Link to=\"/\" activeOptions={{ exact: true }}>\n Home\n </Link>\n)\n```\n\nThis will ensure that the link is not active when you are a child route.\n\nA few more options to be aware of:\n\n- If you want to include the hash in your matching, you can pass the `includeHash: true` option\n- If you do **not** want to include the search params in your matching, you can pass the `includeSearch: false` option\n\n### Passing `isActive` to children\n\nThe `Link` component accepts a function for its children, allowing you to propagate its `isActive` property to children. For example, you could style a child component based on whether the parent link is active:\n\n```tsx\nconst link = (\n <Link to=\"/blog/post\">\n {({ isActive }) => {\n return (\n <>\n <span>My Blog Post</span>\n <icon className={isActive ? 'active' : 'inactive'} />\n </>\n )\n }}\n </Link>\n)\n```\n\n### Link Preloading\n\nThe `Link` component supports automatically preloading routes on intent (hovering or touchstart for now). This can be configured as a default in the router options (which we'll talk more about soon) or by passing a `preload='intent'` prop to the `Link` component. Here's an example:\n\n```tsx\nconst link = (\n <Link to=\"/blog/post/$postId\" preload=\"intent\">\n Blog Post\n </Link>\n)\n```\n\nWith preloading enabled and relatively quick asynchronous route dependencies (if any), this simple trick can increase the perceived performance of your application with very little effort.\n\nWhat's even better is that by using a cache-first library like `@tanstack/query`, preloaded routes will stick around and be ready for a stale-while-revalidate experience if the user decides to navigate to the route later on.\n\n### Link Preloading Delay\n\nAlong with preloading is a configurable delay which determines how long a user must hover over a link to trigger the intent-based preloading. The default delay is 50 milliseconds, but you can change this by passing a `preloadDelay` prop to the `Link` component with the number of milliseconds you'd like to wait:\n\n```tsx\nconst link = (\n <Link to=\"/blog/post/$postId\" preload=\"intent\" preloadDelay={100}>\n Blog Post\n </Link>\n)\n```\n\n## `useNavigate`\n\n> \u26A0\uFE0F Because of the `Link` component's built-in affordances around `href`, cmd/ctrl + click-ability, and active/inactive capabilities, it's recommended to use the `Link` component instead of `useNavigate` for anything the user can interact with (e.g. links, buttons). However, there are some cases where `useNavigate` is necessary to handle side-effect navigations (e.g. a successful async action that results in a navigation).\n\nThe `useNavigate` hook returns a `navigate` function that can be called to imperatively navigate. It's a great way to navigate to a route from a side-effect (e.g. a successful async action). Here's an example:\n\n```tsx\nfunction Component() {\n const navigate = useNavigate({ from: '/posts/$postId' })\n\n const handleSubmit = async (e: FrameworkFormEvent) => {\n e.preventDefault()\n\n const response = await fetch('/posts', {\n method: 'POST',\n body: JSON.stringify({ title: 'My First Post' }),\n })\n\n const { id: postId } = await response.json()\n\n if (response.ok) {\n navigate({ to: '/posts/$postId', params: { postId } })\n }\n }\n}\n```\n\n> \uD83E\uDDE0 As shown above, you can pass the `from` option to specify the route to navigate from in the hook call. While this is also possible to pass in the resulting `navigate` function each time you call it, it's recommended to pass it here to reduce on potential error and also not type as much!\n\n### `navigate` Options\n\nThe `navigate` function returned by `useNavigate` accepts the [`NavigateOptions` interface](#navigateoptions-interface)\n\n## `Navigate` Component\n\nOccasionally, you may find yourself needing to navigate immediately when a component mounts. Your first instinct might be to reach for `useNavigate` and an immediate side-effect (e.g. useEffect), but this is unnecessary. Instead, you can render the `Navigate` component to achieve the same result:\n\n```tsx\nfunction Component() {\n return <Navigate to=\"/posts/$postId\" params={{ postId: 'my-first-post' }} />\n}\n```\n\nThink of the `Navigate` component as a way to navigate to a route immediately when a component mounts. It's a great way to handle client-only redirects. It is _definitely not_ a substitute for handling server-aware redirects responsibly on the server.\n\n## `router.navigate`\n\nThe `router.navigate` method is the same as the `navigate` function returned by `useNavigate` and accepts the same [`NavigateOptions` interface](#navigateoptions-interface). Unlike the `useNavigate` hook, it is available anywhere your `router` instance is available and is thus a great way to navigate imperatively from anywhere in your application, including outside of your framework.\n\n## `useMatchRoute` and `<MatchRoute>`\n\nThe `useMatchRoute` hook and `<MatchRoute>` component are the same thing, but the hook is a bit more flexible. They both accept the standard navigation `ToOptions` interface either as options or props and return `true/false` if that route is currently matched. It also has a handy `pending` option that will return `true` if the route is currently pending (e.g. a route is currently transitioning to that route). This can be extremely useful for showing optimistic UI around where a user is navigating:\n\n```tsx\nfunction Component() {\n return (\n <div>\n <Link to=\"/users\">\n Users\n <MatchRoute to=\"/users\" pending>\n <Spinner />\n </MatchRoute>\n </Link>\n </div>\n )\n}\n```\n\nThe component version `<MatchRoute>` can also be used with a function as children to render something when the route is matched:\n\n```tsx\nfunction Component() {\n return (\n <div>\n <Link to=\"/users\">\n Users\n <MatchRoute to=\"/users\" pending>\n {(match) => {\n return <Spinner show={match} />\n }}\n </MatchRoute>\n </Link>\n </div>\n )\n}\n```\n\nThe hook version `useMatchRoute` returns a function that can be called programmatically to check if a route is matched:\n\n```tsx\nfunction Component() {\n const matchRoute = useMatchRoute()\n\n useEffect(() => {\n if (matchRoute({ to: '/users', pending: true })) {\n console.info('The /users route is matched and pending')\n }\n })\n\n return (\n <div>\n <Link to=\"/users\">Users</Link>\n </div>\n )\n}\n```\n\n---\n\nPhew! That's a lot of navigating! That said, hopefully you're feeling pretty good about getting around your application now. Let's move on!\n\n# Not Found Errors\n\n> \u26A0\uFE0F This page covers the newer `notFound` function and `notFoundComponent` API for handling not found errors. The `NotFoundRoute` route is deprecated and will be removed in a future release. See [Migrating from `NotFoundRoute`](#migrating-from-notfoundroute) for more information.\n\n## Overview\n\nThere are 2 uses for not-found errors in TanStack Router:\n\n- **Non-matching route paths**: When a path does not match any known route matching pattern **OR** when it partially matches a route, but with extra path segments\n - The **router** will automatically throw a not-found error when a path does not match any known route matching pattern\n - If the router's `notFoundMode` is set to `fuzzy`, the nearest parent route with a `notFoundComponent` will handle the error. If the router's `notFoundMode` is set to `root`, the root route will handle the error.\n - Examples:\n - Attempting to access `/users` when there is no `/users` route\n - Attempting to access `/posts/1/edit` when the route tree only handles `/posts/$postId`\n- **Missing resources**: When a resource cannot be found, such as a post with a given ID or any asynchronous data that is not available or does not exist\n - **You, the developer** must throw a not-found error when a resource cannot be found. This can be done in the `beforeLoad` or `loader` functions using the `notFound` utility.\n - Will be handled by the nearest parent route with a `notFoundComponent` (when `notFound` is called within `loader`) or the root route.\n - Examples:\n - Attempting to access `/posts/1` when the post with ID 1 does not exist\n - Attempting to access `/docs/path/to/document` when the document does not exist\n\nUnder the hood, both of these cases are implemented using the same `notFound` function and `notFoundComponent` API.\n\n## The `notFoundMode` option\n\nWhen TanStack Router encounters a **pathname** that doesn't match any known route pattern **OR** partially matches a route pattern but with extra trailing pathname segments, it will automatically throw a not-found error.\n\nDepending on the `notFoundMode` option, the router will handle these automatic errors differently::\n\n- [\"fuzzy\" mode](#notfoundmode-fuzzy) (default): The router will intelligently find the closest matching suitable route and display the `notFoundComponent`.\n- [\"root\" mode](#notfoundmode-root): All not-found errors will be handled by the root route's `notFoundComponent`, regardless of the nearest matching route.\n\n### `notFoundMode: 'fuzzy'`\n\nBy default, the router's `notFoundMode` is set to `fuzzy`, which indicates that if a pathname doesn't match any known route, the router will attempt to use the closest matching route with children/(an outlet) and a configured not found component.\n\n> **\u2753 Why is this the default?** Fuzzy matching to preserve as much parent layout as possible for the user gives them more context to navigate to a useful location based on where they thought they would arrive.\n\nThe nearest suitable route is found using the following criteria:\n\n- The route must have children and therefore an `Outlet` to render the `notFoundComponent`\n- The route must have a `notFoundComponent` configured or the router must have a `defaultNotFoundComponent` configured\n\nFor example, consider the following route tree:\n\n- `__root__` (has a `notFoundComponent` configured)\n - `posts` (has a `notFoundComponent` configured)\n - `$postId` (has a `notFoundComponent` configured)\n\nIf provided the path of `/posts/1/edit`, the following component structure will be rendered:\n\n- `<Root>`\n - `<Posts>`\n - `<Posts.notFoundComponent>`\n\nThe `notFoundComponent` of the `posts` route will be rendered because it is the **nearest suitable parent route with children (and therefore an outlet) and a `notFoundComponent` configured**.\n\n### `notFoundMode: 'root'`\n\nWhen `notFoundMode` is set to `root`, all not-found errors will be handled by the root route's `notFoundComponent` instead of bubbling up from the nearest fuzzy-matched route.\n\nFor example, consider the following route tree:\n\n- `__root__` (has a `notFoundComponent` configured)\n - `posts` (has a `notFoundComponent` configured)\n - `$postId` (has a `notFoundComponent` configured)\n\nIf provided the path of `/posts/1/edit`, the following component structure will be rendered:\n\n- `<Root>`\n - `<Root.notFoundComponent>`\n\nThe `notFoundComponent` of the `__root__` route will be rendered because the `notFoundMode` is set to `root`.\n\n## Configuring a route's `notFoundComponent`\n\nTo handle both types of not-found errors, you can attach a `notFoundComponent` to a route. This component will be rendered when a not-found error is thrown.\n\nFor example, configuring a `notFoundComponent` for a `/settings` route to handle non-existing settings pages:\n\n```tsx\nexport const Route = createFileRoute('/settings')({\n component: () => {\n return (\n <div>\n <p>Settings page</p>\n <Outlet />\n </div>\n )\n },\n notFoundComponent: () => {\n return <p>This setting page doesn't exist!</p>\n },\n})\n```\n\nOr configuring a `notFoundComponent` for a `/posts/$postId` route to handle posts that don't exist:\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params: { postId } }) => {\n const post = await getPost(postId)\n if (!post) throw notFound()\n return { post }\n },\n component: ({ post }) => {\n return (\n <div>\n <h1>{post.title}</h1>\n <p>{post.body}</p>\n </div>\n )\n },\n notFoundComponent: () => {\n return <p>Post not found!</p>\n },\n})\n```\n\n## Default Router-Wide Not Found Handling\n\nYou may want to provide a default not-found component for every route in your app with child routes.\n\n> Why only routes with children? **Leaf-node routes (routes without children) will never render an `Outlet` and therefore are not able to handle not-found errors.**\n\nTo do this, pass a `defaultNotFoundComponent` to the `createRouter` function:\n\n```tsx\nconst router = createRouter({\n defaultNotFoundComponent: () => {\n return (\n <div>\n <p>Not found!</p>\n <Link to=\"/\">Go home</Link>\n </div>\n )\n },\n})\n```\n\n## Throwing your own `notFound` errors\n\nYou can manually throw not-found errors in loader methods and components using the `notFound` function. This is useful when you need to signal that a resource cannot be found.\n\nThe `notFound` function works in a similar fashion to the `redirect` function. To cause a not-found error, you can **throw a `notFound()`**.\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params: { postId } }) => {\n // Returns `null` if the post doesn't exist\n const post = await getPost(postId)\n if (!post) {\n throw notFound()\n // Alternatively, you can make the notFound function throw:\n // notFound({ throw: true })\n }\n // Post is guaranteed to be defined here because we threw an error\n return { post }\n },\n})\n```\n\nThe not-found error above will be handled by the same route or nearest parent route that has either a `notFoundComponent` route option or the `defaultNotFoundComponent` router option configured.\n\nIf neither the route nor any suitable parent route is found to handle the error, the root route will handle it using TanStack Router's **extremely basic (and purposefully undesirable)** default not-found component that simply renders `<p>Not Found</p>`. It's highly recommended to either attach at least one `notFoundComponent` to the root route or configure a router-wide `defaultNotFoundComponent` to handle not-found errors.\n\n> \u26A0\uFE0F Throwing a notFound error in a beforeLoad method will always trigger the __root notFoundComponent. Since beforeLoad methods are run prior to the route loader methods, there is no guarantee that any required data for layouts have successfully loaded before the error is thrown.\n\n## Specifying Which Routes Handle Not Found Errors\n\nSometimes you may want to trigger a not-found on a specific parent route and bypass the normal not-found component propagation. To do this, pass in a route id to the `route` option in the `notFound` function.\n\n```tsx\n// _pathlessLayout.tsx\nexport const Route = createFileRoute('/_pathlessLayout')({\n // This will render\n notFoundComponent: () => {\n return <p>Not found (in _pathlessLayout)</p>\n },\n component: () => {\n return (\n <div>\n <p>This is a pathless layout route!</p>\n <Outlet />\n </div>\n )\n },\n})\n\n// _pathlessLayout/route-a.tsx\nexport const Route = createFileRoute('/_pathless/route-a')({\n loader: async () => {\n // This will make LayoutRoute handle the not-found error\n throw notFound({ routeId: '/_pathlessLayout' })\n // ^^^^^^^^^ This will autocomplete from the registered router\n },\n // This WILL NOT render\n notFoundComponent: () => {\n return <p>Not found (in _pathlessLayout/route-a)</p>\n },\n})\n```\n\n### Manually targeting the root route\n\nYou can also target the root route by passing the exported `rootRouteId` variable to the `notFound` function's `route` property:\n\n```tsx\nimport { rootRouteId } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params: { postId } }) => {\n const post = await getPost(postId)\n if (!post) throw notFound({ routeId: rootRouteId })\n return { post }\n },\n})\n```\n\n### Throwing Not Found Errors in Components\n\nYou can also throw not-found errors in components. However, **it is recommended to throw not-found errors in loader methods instead of components in order to correctly type loader data and prevent flickering.**\n\nTanStack Router exposes a `CatchNotFound` component similar to `CatchBoundary` that can be used to catch not-found errors in components and display UI accordingly.\n\n### Data Loading Inside `notFoundComponent`\n\n`notFoundComponent` is a special case when it comes to data loading. **`SomeRoute.useLoaderData` may not be defined depending on which route you are trying to access and where the not-found error gets thrown**. However, `Route.useParams`, `Route.useSearch`, `Route.useRouteContext`, etc. will return a defined value.\n\n**If you need to pass incomplete loader data to `notFoundComponent`,** pass the data via the `data` option in the `notFound` function and validate it in `notFoundComponent`.\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params: { postId } }) => {\n const post = await getPost(postId)\n if (!post)\n throw notFound({\n // Forward some data to the notFoundComponent\n // data: someIncompleteLoaderData\n })\n return { post }\n },\n // `data: unknown` is passed to the component via the `data` option when calling `notFound`\n notFoundComponent: ({ data }) => {\n // \u274C useLoaderData is not valid here: const { post } = Route.useLoaderData()\n\n // \u2705:\n const { postId } = Route.useParams()\n const search = Route.useSearch()\n const context = Route.useRouteContext()\n\n return <p>Post with id {postId} not found!</p>\n },\n})\n```\n\n## Usage With SSR\n\nSee [SSR guide](./ssr.md) for more information.\n\n## Migrating from `NotFoundRoute`\n\nThe `NotFoundRoute` API is deprecated in favor of `notFoundComponent`. The `NotFoundRoute` API will be removed in a future release.\n\n**The `notFound` function and `notFoundComponent` will not work when using `NotFoundRoute`.**\n\nThe main differences are:\n\n- `NotFoundRoute` is a route that requires an `<Outlet>` on its parent route to render. `notFoundComponent` is a component that can be attached to any route.\n- When using `NotFoundRoute`, you can't use layouts. `notFoundComponent` can be used with layouts.\n- When using `notFoundComponent`, path matching is strict. This means that if you have a route at `/post/$postId`, a not-found error will be thrown if you try to access `/post/1/2/3`. With `NotFoundRoute`, `/post/1/2/3` would match the `NotFoundRoute` and only render it if there is an `<Outlet>`.\n\nTo migrate from `NotFoundRoute` to `notFoundComponent`, you'll just need to make a few changes:\n\n```tsx\n// router.tsx\nimport { createRouter } from '@tanstack/react-router'\nimport { routeTree } from './routeTree.gen.'\n- import { notFoundRoute } from './notFoundRoute' // [!code --]\n\nexport const router = createRouter({\n routeTree,\n- notFoundRoute // [!code --]\n})\n\n// routes/__root.tsx\nimport { createRootRoute } from '@tanstack/react-router'\n\nexport const Route = createRootRoute({\n // ...\n+ notFoundComponent: () => { // [!code ++]\n+ return <p>Not found!</p> // [!code ++]\n+ } // [!code ++]\n})\n```\n\nImportant changes:\n\n- A `notFoundComponent` is added to the root route for global not-found handling.\n - You can also add a `notFoundComponent` to any other route in your route tree to handle not-found errors for that specific route.\n- The `notFoundComponent` does not support rendering an `<Outlet>`.\n\n# Outlets\n\nNested routing means that routes can be nested within other routes, including the way they render. So how do we tell our routes where to render this nested content?\n\n## The `Outlet` Component\n\nThe `Outlet` component is used to render the next potentially matching child route. `<Outlet />` doesn't take any props and can be rendered anywhere within a route's component tree. If there is no matching child route, `<Outlet />` will render `null`.\n\n> [!TIP]\n> If a route's `component` is left undefined, it will render an `<Outlet />` automatically.\n\nA great example is configuring the root route of your application. Let's give our root route a component that renders a title, then an `<Outlet />` for our top-level routes to render.\n\n```tsx\nimport { createRootRoute, Outlet } from '@tanstack/react-router'\n\nexport const Route = createRootRoute({\n component: RootComponent,\n})\n\nfunction RootComponent() {\n return (\n <div>\n <h1>My App</h1>\n <Outlet /> {/* This is where child routes will render */}\n </div>\n )\n}\n```\n\n# Parallel Routes\n\nWe haven't covered this yet. Stay tuned!\n\n# Path Params\n\nPath params are used to match a single segment (the text until the next `/`) and provide its value back to you as a **named** variable. They are defined by using the `$` character prefix in the path, followed by the key variable to assign it to. The following are valid path param paths:\n\n- `$postId`\n- `$name`\n- `$teamId`\n- `about/$name`\n- `team/$teamId`\n- `blog/$postId`\n\nBecause path param routes only match to the next `/`, child routes can be created to continue expressing hierarchy:\n\nLet's create a post route file that uses a path param to match the post ID:\n\n- `posts.$postId.tsx`\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params }) => {\n return fetchPost(params.postId)\n },\n})\n```\n\n## Path Params can be used by child routes\n\nOnce a path param has been parsed, it is available to all child routes. This means that if we define a child route to our `postRoute`, we can use the `postId` variable from the URL in the child route's path!\n\n## Path Params in Loaders\n\nPath params are passed to the loader as a `params` object. The keys of this object are the names of the path params, and the values are the values that were parsed out of the actual URL path. For example, if we were to visit the `/blog/123` URL, the `params` object would be `{ postId: '123' }`:\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params }) => {\n return fetchPost(params.postId)\n },\n})\n```\n\nThe `params` object is also passed to the `beforeLoad` option:\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n beforeLoad: async ({ params }) => {\n // do something with params.postId\n },\n})\n```\n\n## Path Params in Components\n\nIf we add a component to our `postRoute`, we can access the `postId` variable from the URL by using the route's `useParams` hook:\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId')({\n component: PostComponent,\n})\n\nfunction PostComponent() {\n const { postId } = Route.useParams()\n return <div>Post {postId}</div>\n}\n```\n\n> \uD83E\uDDE0 Quick tip: If your component is code-split, you can use the [getRouteApi function](./code-splitting.md#manually-accessing-route-apis-in-other-files-with-the-getrouteapi-helper) to avoid having to import the `Route` configuration to get access to the typed `useParams()` hook.\n\n## Path Params outside of Routes\n\nYou can also use the globally exported `useParams` hook to access any parsed path params from any component in your app. You'll need to pass the `strict: false` option to `useParams`, denoting that you want to access the params from an ambiguous location:\n\n```tsx\nfunction PostComponent() {\n const { postId } = useParams({ strict: false })\n return <div>Post {postId}</div>\n}\n```\n\n## Navigating with Path Params\n\nWhen navigating to a route with path params, TypeScript will require you to pass the params either as an object or as a function that returns an object of params.\n\nLet's see what an object style looks like:\n\n```tsx\nfunction Component() {\n return (\n <Link to=\"/blog/$postId\" params={{ postId: '123' }}>\n Post 123\n </Link>\n )\n}\n```\n\nAnd here's what a function style looks like:\n\n```tsx\nfunction Component() {\n return (\n <Link to=\"/blog/$postId\" params={(prev) => ({ ...prev, postId: '123' })}>\n Post 123\n </Link>\n )\n}\n```\n\nNotice that the function style is useful when you need to persist params that are already in the URL for other routes. This is because the function style will receive the current params as an argument, allowing you to modify them as needed and return the final params object.\n\n## Prefixes and Suffixes for Path Params\n\nYou can also use **prefixes** and **suffixes** with path params to create more complex routing patterns. This allows you to match specific URL structures while still capturing the dynamic segments.\n\nWhen using either prefixes or suffixes, you can define them by wrapping the path param in curly braces `{}` and placing the prefix or suffix before or after the variable name.\n\n### Defining Prefixes\n\nPrefixes are defined by placing the prefix text outside the curly braces before the variable name. For example, if you want to match a URL that starts with `post-` followed by a post ID, you can define it like this:\n\n```tsx\n// src/routes/posts/post-{$postId}.tsx\nexport const Route = createFileRoute('/posts/post-{$postId}')({\n component: PostComponent,\n})\n\nfunction PostComponent() {\n const { postId } = Route.useParams()\n // postId will be the value after 'post-'\n return <div>Post ID: {postId}</div>\n}\n```\n\nYou can even combines prefixes with wildcard routes to create more complex patterns:\n\n```tsx\n// src/routes/on-disk/storage-{$}\nexport const Route = createFileRoute('/on-disk/storage-{$postId}/$')({\n component: StorageComponent,\n})\n\nfunction StorageComponent() {\n const { _splat } = Route.useParams()\n // _splat, will be value after 'storage-'\n // i.e. my-drive/documents/foo.txt\n return <div>Storage Location: /{_splat}</div>\n}\n```\n\n### Defining Suffixes\n\nSuffixes are defined by placing the suffix text outside the curly braces after the variable name. For example, if you want to match a URL a filename that ends with `txt`, you can define it like this:\n\n```tsx\n// src/routes/files/{$fileName}txt\nexport const Route = createFileRoute('/files/{$fileName}.txt')({\n component: FileComponent,\n})\n\nfunction FileComponent() {\n const { fileName } = Route.useParams()\n // fileName will be the value before 'txt'\n return <div>File Name: {fileName}</div>\n}\n```\n\nYou can also combine suffixes with wildcards for more complex routing patterns:\n\n```tsx\n// src/routes/files/{$}[.]txt\nexport const Route = createFileRoute('/files/{$fileName}[.]txt')({\n component: FileComponent,\n})\n\nfunction FileComponent() {\n const { _splat } = Route.useParams()\n // _splat will be the value before '.txt'\n return <div>File Splat: {_splat}</div>\n}\n```\n\n### Combining Prefixes and Suffixes\n\nYou can combine both prefixes and suffixes to create very specific routing patterns. For example, if you want to match a URL that starts with `user-` and ends with `.json`, you can define it like this:\n\n```tsx\n// src/routes/users/user-{$userId}.json\nexport const Route = createFileRoute('/users/user-{$userId}.json')({\n component: UserComponent,\n})\n\nfunction UserComponent() {\n const { userId } = Route.useParams()\n // userId will be the value between 'user-' and '.json'\n return <div>User ID: {userId}</div>\n}\n```\n\nSimilar to the previous examples, you can also use wildcards with prefixes and suffixes. Go wild!\n\n## Optional Path Parameters\n\nOptional path parameters allow you to define route segments that may or may not be present in the URL. They use the `{-$paramName}` syntax and provide flexible routing patterns where certain parameters are optional.\n\n### Defining Optional Parameters\n\nOptional path parameters are defined using curly braces with a dash prefix: `{-$paramName}`\n\n```tsx\n// Single optional parameter\n// src/routes/posts/{-$category}.tsx\nexport const Route = createFileRoute('/posts/{-$category}')({\n component: PostsComponent,\n})\n\n// Multiple optional parameters\n// src/routes/posts/{-$category}/{-$slug}.tsx\nexport const Route = createFileRoute('/posts/{-$category}/{-$slug}')({\n component: PostComponent,\n})\n\n// Mixed required and optional parameters\n// src/routes/users/$id/{-$tab}.tsx\nexport const Route = createFileRoute('/users/$id/{-$tab}')({\n component: UserComponent,\n})\n```\n\n### How Optional Parameters Work\n\nOptional parameters create flexible URL patterns:\n\n- `/posts/{-$category}` matches both `/posts` and `/posts/tech`\n- `/posts/{-$category}/{-$slug}` matches `/posts`, `/posts/tech`, and `/posts/tech/hello-world`\n- `/users/$id/{-$tab}` matches `/users/123` and `/users/123/settings`\n\nWhen an optional parameter is not present in the URL, its value will be `undefined` in your route handlers and components.\n\n### Accessing Optional Parameters\n\nOptional parameters work exactly like regular parameters in your components, but their values may be `undefined`:\n\n```tsx\nfunction PostsComponent() {\n const { category } = Route.useParams()\n\n return <div>{category ? `Posts in ${category}` : 'All Posts'}</div>\n}\n```\n\n### Optional Parameters in Loaders\n\nOptional parameters are available in loaders and may be `undefined`:\n\n```tsx\nexport const Route = createFileRoute('/posts/{-$category}')({\n loader: async ({ params }) => {\n // params.category might be undefined\n return fetchPosts({ category: params.category })\n },\n})\n```\n\n### Optional Parameters in beforeLoad\n\nOptional parameters work in `beforeLoad` handlers as well:\n\n```tsx\nexport const Route = createFileRoute('/posts/{-$category}')({\n beforeLoad: async ({ params }) => {\n if (params.category) {\n // Validate category exists\n await validateCategory(params.category)\n }\n },\n})\n```\n\n### Advanced Optional Parameter Patterns\n\n#### With Prefix and Suffix\n\nOptional parameters support prefix and suffix patterns:\n\n```tsx\n// File route: /files/prefix{-$name}.txt\n// Matches: /files/prefix.txt and /files/prefixdocument.txt\nexport const Route = createFileRoute('/files/prefix{-$name}.txt')({\n component: FileComponent,\n})\n\nfunction FileComponent() {\n const { name } = Route.useParams()\n return <div>File: {name || 'default'}</div>\n}\n```\n\n#### All Optional Parameters\n\nYou can create routes where all parameters are optional:\n\n```tsx\n// Route: /{-$year}/{-$month}/{-$day}\n// Matches: /, /2023, /2023/12, /2023/12/25\nexport const Route = createFileRoute('/{-$year}/{-$month}/{-$day}')({\n component: DateComponent,\n})\n\nfunction DateComponent() {\n const { year, month, day } = Route.useParams()\n\n if (!year) return <div>Select a year</div>\n if (!month) return <div>Year: {year}</div>\n if (!day)\n return (\n <div>\n Month: {year}/{month}\n </div>\n )\n\n return (\n <div>\n Date: {year}/{month}/{day}\n </div>\n )\n}\n```\n\n#### Optional Parameters with Wildcards\n\nOptional parameters can be combined with wildcards for complex routing patterns:\n\n```tsx\n// Route: /docs/{-$version}/$\n// Matches: /docs/extra/path, /docs/v2/extra/path\nexport const Route = createFileRoute('/docs/{-$version}/$')({\n component: DocsComponent,\n})\n\nfunction DocsComponent() {\n const { version } = Route.useParams()\n const { _splat } = Route.useParams()\n\n return (\n <div>\n Version: {version || 'latest'}\n Path: {_splat}\n </div>\n )\n}\n```\n\n### Navigating with Optional Parameters\n\nWhen navigating to routes with optional parameters, you have fine-grained control over which parameters to include:\n\n```tsx\nfunction Navigation() {\n return (\n <div>\n {/* Navigate with optional parameter */}\n <Link to=\"/posts/{-$category}\" params={{ category: 'tech' }}>\n Tech Posts\n </Link>\n\n {/* Navigate without optional parameter */}\n <Link to=\"/posts/{-$category}\" params={{ category: undefined }}>\n All Posts\n </Link>\n\n {/* Navigate with multiple optional parameters */}\n <Link\n to=\"/posts/{-$category}/{-$slug}\"\n params={{ category: 'tech', slug: 'react-tips' }}\n >\n Specific Post\n </Link>\n </div>\n )\n}\n```\n\n### Type Safety with Optional Parameters\n\nTypeScript provides full type safety for optional parameters:\n\n```tsx\nfunction PostsComponent() {\n // TypeScript knows category might be undefined\n const { category } = Route.useParams() // category: string | undefined\n\n // Safe navigation\n const categoryUpper = category?.toUpperCase()\n\n return <div>{categoryUpper || 'All Categories'}</div>\n}\n\n// Navigation is type-safe and flexible\n<Link\n to=\"/posts/{-$category}\"\n params={{ category: 'tech' }} // \u2705 Valid - string\n>\n Tech Posts\n</Link>\n\n<Link\n to=\"/posts/{-$category}\"\n params={{ category: 123 }} // \u2705 Valid - number (auto-stringified)\n>\n Category 123\n</Link>\n```\n\n## Internationalization (i18n) with Optional Path Parameters\n\nOptional path parameters are excellent for implementing internationalization (i18n) routing patterns. You can use prefix patterns to handle multiple languages while maintaining clean, SEO-friendly URLs.\n\n### Prefix-based i18n\n\nUse optional language prefixes to support URLs like `/en/about`, `/fr/about`, or just `/about` (default language):\n\n```tsx\n// Route: /{-$locale}/about\nexport const Route = createFileRoute('/{-$locale}/about')({\n component: AboutComponent,\n})\n\nfunction AboutComponent() {\n const { locale } = Route.useParams()\n const currentLocale = locale || 'en' // Default to English\n\n const content = {\n en: { title: 'About Us', description: 'Learn more about our company.' },\n fr: {\n title: '\u00C0 Propos',\n description: 'En savoir plus sur notre entreprise.',\n },\n es: {\n title: 'Acerca de',\n description: 'Conoce m\u00E1s sobre nuestra empresa.',\n },\n }\n\n return (\n <div>\n <h1>{content[currentLocale]?.title}</h1>\n <p>{content[currentLocale]?.description}</p>\n </div>\n )\n}\n```\n\nThis pattern matches:\n\n- `/about` (default locale)\n- `/en/about` (explicit English)\n- `/fr/about` (French)\n- `/es/about` (Spanish)\n\n### Complex i18n Patterns\n\nCombine optional parameters for more sophisticated i18n routing:\n\n```tsx\n// Route: /{-$locale}/blog/{-$category}/$slug\nexport const Route = createFileRoute('/{-$locale}/blog/{-$category}/$slug')({\n beforeLoad: async ({ params }) => {\n const locale = params.locale || 'en'\n const category = params.category\n\n // Validate locale and category\n const validLocales = ['en', 'fr', 'es', 'de']\n if (locale && !validLocales.includes(locale)) {\n throw new Error('Invalid locale')\n }\n\n return { locale, category }\n },\n loader: async ({ params, context }) => {\n const { locale } = context\n const { slug, category } = params\n\n return fetchBlogPost({ slug, category, locale })\n },\n component: BlogPostComponent,\n})\n\nfunction BlogPostComponent() {\n const { locale, category, slug } = Route.useParams()\n const data = Route.useLoaderData()\n\n return (\n <article>\n <h1>{data.title}</h1>\n <p>\n Category: {category || 'All'} | Language: {locale || 'en'}\n </p>\n <div>{data.content}</div>\n </article>\n )\n}\n```\n\nThis supports URLs like:\n\n- `/blog/tech/my-post` (default locale, tech category)\n- `/fr/blog/my-post` (French, no category)\n- `/en/blog/tech/my-post` (explicit English, tech category)\n- `/es/blog/tecnologia/mi-post` (Spanish, Spanish category)\n\n### Language Navigation\n\nCreate language switchers using optional i18n parameters with function-style params:\n\n```tsx\nfunction LanguageSwitcher() {\n const currentParams = useParams({ strict: false })\n\n const languages = [\n { code: 'en', name: 'English' },\n { code: 'fr', name: 'Fran\u00E7ais' },\n { code: 'es', name: 'Espa\u00F1ol' },\n ]\n\n return (\n <div className=\"language-switcher\">\n {languages.map(({ code, name }) => (\n <Link\n key={code}\n to=\"/{-$locale}/blog/{-$category}/$slug\"\n params={(prev) => ({\n ...prev,\n locale: code === 'en' ? undefined : code, // Remove 'en' for clean URLs\n })}\n className={currentParams.locale === code ? 'active' : ''}\n >\n {name}\n </Link>\n ))}\n </div>\n )\n}\n```\n\nYou can also create more sophisticated language switching logic:\n\n```tsx\nfunction AdvancedLanguageSwitcher() {\n const currentParams = useParams({ strict: false })\n\n const handleLanguageChange = (newLocale: string) => {\n return (prev: any) => {\n // Preserve all existing params but update locale\n const updatedParams = { ...prev }\n\n if (newLocale === 'en') {\n // Remove locale for clean English URLs\n delete updatedParams.locale\n } else {\n updatedParams.locale = newLocale\n }\n\n return updatedParams\n }\n }\n\n return (\n <div className=\"language-switcher\">\n <Link\n to=\"/{-$locale}/blog/{-$category}/$slug\"\n params={handleLanguageChange('fr')}\n >\n Fran\u00E7ais\n </Link>\n\n <Link\n to=\"/{-$locale}/blog/{-$category}/$slug\"\n params={handleLanguageChange('es')}\n >\n Espa\u00F1ol\n </Link>\n\n <Link\n to=\"/{-$locale}/blog/{-$category}/$slug\"\n params={handleLanguageChange('en')}\n >\n English\n </Link>\n </div>\n )\n}\n```\n\n### Advanced i18n with Optional Parameters\n\nOrganize i18n routes using optional parameters for flexible locale handling:\n\n```tsx\n// Route structure:\n// routes/\n// {-$locale}/\n// index.tsx // /, /en, /fr\n// about.tsx // /about, /en/about, /fr/about\n// blog/\n// index.tsx // /blog, /en/blog, /fr/blog\n// $slug.tsx // /blog/post, /en/blog/post, /fr/blog/post\n\n// routes/{-$locale}/index.tsx\nexport const Route = createFileRoute('/{-$locale}/')({\n component: HomeComponent,\n})\n\nfunction HomeComponent() {\n const { locale } = Route.useParams()\n const isRTL = ['ar', 'he', 'fa'].includes(locale || '')\n\n return (\n <div dir={isRTL ? 'rtl' : 'ltr'}>\n <h1>Welcome ({locale || 'en'})</h1>\n {/* Localized content */}\n </div>\n )\n}\n\n// routes/{-$locale}/about.tsx\nexport const Route = createFileRoute('/{-$locale}/about')({\n component: AboutComponent,\n})\n```\n\n### SEO and Canonical URLs\n\nHandle SEO for i18n routes properly:\n\n```tsx\nexport const Route = createFileRoute('/{-$locale}/products/$id')({\n component: ProductComponent,\n head: ({ params, loaderData }) => {\n const locale = params.locale || 'en'\n const product = loaderData\n\n return {\n title: product.title[locale] || product.title.en,\n meta: [\n {\n name: 'description',\n content: product.description[locale] || product.description.en,\n },\n {\n property: 'og:locale',\n content: locale,\n },\n ],\n links: [\n // Canonical URL (always use default locale format)\n {\n rel: 'canonical',\n href: `https://example.com/products/${params.id}`,\n },\n // Alternate language versions\n {\n rel: 'alternate',\n hreflang: 'en',\n href: `https://example.com/products/${params.id}`,\n },\n {\n rel: 'alternate',\n hreflang: 'fr',\n href: `https://example.com/fr/products/${params.id}`,\n },\n {\n rel: 'alternate',\n hreflang: 'es',\n href: `https://example.com/es/products/${params.id}`,\n },\n ],\n }\n },\n})\n```\n\n### Type Safety for i18n\n\nEnsure type safety for your i18n implementations:\n\n```tsx\n// Define supported locales\ntype Locale = 'en' | 'fr' | 'es' | 'de'\n\n// Type-safe locale validation\nfunction validateLocale(locale: string | undefined): locale is Locale {\n return ['en', 'fr', 'es', 'de'].includes(locale as Locale)\n}\n\nexport const Route = createFileRoute('/{-$locale}/shop/{-$category}')({\n beforeLoad: async ({ params }) => {\n const { locale } = params\n\n // Type-safe locale validation\n if (locale && !validateLocale(locale)) {\n throw redirect({\n to: '/shop/{-$category}',\n params: { category: params.category },\n })\n }\n\n return {\n locale: (locale as Locale) || 'en',\n isDefaultLocale: !locale || locale === 'en',\n }\n },\n component: ShopComponent,\n})\n\nfunction ShopComponent() {\n const { locale, category } = Route.useParams()\n const { isDefaultLocale } = Route.useRouteContext()\n\n // TypeScript knows locale is Locale | undefined\n // and we have validated it in beforeLoad\n\n return (\n <div>\n <h1>Shop {category ? `- ${category}` : ''}</h1>\n <p>Language: {locale || 'en'}</p>\n {!isDefaultLocale && (\n <Link to=\"/shop/{-$category}\" params={{ category }}>\n View in English\n </Link>\n )}\n </div>\n )\n}\n```\n\nOptional path parameters provide a powerful and flexible foundation for implementing internationalization in your TanStack Router applications. Whether you prefer prefix-based or combined approaches, you can create clean, SEO-friendly URLs while maintaining excellent developer experience and type safety.\n\n## Allowed Characters\n\nBy default, path params are escaped with `encodeURIComponent`. If you want to allow other valid URI characters (e.g. `@` or `+`), you can specify that in your [RouterOptions](../api/router/RouterOptionsType.md#pathparamsallowedcharacters-property).\n\nExample usage:\n\n```tsx\nconst router = createRouter({\n // ...\n pathParamsAllowedCharacters: ['@'],\n})\n```\n\nThe following is the list of accepted allowed characters:\n\n- `;`\n- `:`\n- `@`\n- `&`\n- `=`\n- `+`\n- `$`\n- `,`\n\n# Preloading\n\nPreloading in TanStack Router is a way to load a route before the user actually navigates to it. This is useful for routes that are likely to be visited by the user next. For example, if you have a list of posts and the user is likely to click on one of them, you can preload the post route so that it's ready to go when the user clicks on it.\n\n## Supported Preloading Strategies\n\n- Intent\n - Preloading by **\"intent\"** works by using hover and touch start events on `<Link>` components to preload the dependencies for the destination route.\n - This strategy is useful for preloading routes that the user is likely to visit next.\n- Viewport Visibility\n - Preloading by **\"viewport**\" works by using the Intersection Observer API to preload the dependencies for the destination route when the `<Link>` component is in the viewport.\n - This strategy is useful for preloading routes that are below the fold or off-screen.\n- Render\n - Preloading by **\"render\"** works by preloading the dependencies for the destination route as soon as the `<Link>` component is rendered in the DOM.\n - This strategy is useful for preloading routes that are always needed.\n\n## How long does preloaded data stay in memory?\n\nPreloaded route matches are temporarily cached in memory with a few important caveats:\n\n- **Unused preloaded data is removed after 30 seconds by default.** This can be configured by setting the `defaultPreloadMaxAge` option on your router.\n- **Obviously, when a route is loaded, its preloaded version is promoted to the router's normal pending matches state.**\n\nIf you need more control over preloading, caching and/or garbage collection of preloaded data, you should use an external caching library like [TanStack Query](https://tanstack.com/query).\n\nThe simplest way to preload routes for your application is to set the `defaultPreload` option to `intent` for your entire router:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n // ...\n defaultPreload: 'intent',\n})\n```\n\nThis will turn on `intent` preloading by default for all `<Link>` components in your application. You can also set the `preload` prop on individual `<Link>` components to override the default behavior.\n\n## Preload Delay\n\nBy default, preloading will start after **50ms** of the user hovering or touching a `<Link>` component. You can change this delay by setting the `defaultPreloadDelay` option on your router:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n // ...\n defaultPreloadDelay: 100,\n})\n```\n\nYou can also set the `preloadDelay` prop on individual `<Link>` components to override the default behavior on a per-link basis.\n\n## Built-in Preloading & `preloadStaleTime`\n\nIf you're using the built-in loaders, you can control how long preloaded data is considered fresh until another preload is triggered by setting either `routerOptions.defaultPreloadStaleTime` or `routeOptions.preloadStaleTime` to a number of milliseconds. **By default, preloaded data is considered fresh for 30 seconds.**.\n\nTo change this, you can set the `defaultPreloadStaleTime` option on your router:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n // ...\n defaultPreloadStaleTime: 10_000,\n})\n```\n\nOr, you can use the `routeOptions.preloadStaleTime` option on individual routes:\n\n```tsx\n// src/routes/posts.$postId.tsx\nexport const Route = createFileRoute('/posts/$postId')({\n loader: async ({ params }) => fetchPost(params.postId),\n // Preload the route again if the preload cache is older than 10 seconds\n preloadStaleTime: 10_000,\n})\n```\n\n## Preloading with External Libraries\n\nWhen integrating external caching libraries like React Query, which have their own mechanisms for determining stale data, you may want to override the default preloading and stale-while-revalidate logic of TanStack Router. These libraries often use options like staleTime to control the freshness of data.\n\nTo customize the preloading behavior in TanStack Router and fully leverage your external library's caching strategy, you can bypass the built-in caching by setting routerOptions.defaultPreloadStaleTime or routeOptions.preloadStaleTime to 0. This ensures that all preloads are marked as stale internally, and loaders are always invoked, allowing your external library, such as React Query, to manage data loading and caching.\n\nFor example:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n // ...\n defaultPreloadStaleTime: 0,\n})\n```\n\nThis would then allow you, for instance, to use an option like React Query's `staleTime` to control the freshness of your preloads.\n\n## Preloading Manually\n\nIf you need to manually preload a route, you can use the router's `preloadRoute` method. It accepts a standard TanStack `NavigateOptions` object and returns a promise that resolves when the route is preloaded.\n\n```tsx\nfunction Component() {\n const router = useRouter()\n\n useEffect(() => {\n async function preload() {\n try {\n const matches = await router.preloadRoute({\n to: postRoute,\n params: { id: 1 },\n })\n } catch (err) {\n // Failed to preload route\n }\n }\n\n preload()\n }, [router])\n\n return <div />\n}\n```\n\nIf you need to preload only the JS chunk of a route, you can use the router's `loadRouteChunk` method. It accepts a route object and returns a promise that resolves when the route chunk is loaded.\n\n```tsx\nfunction Component() {\n const router = useRouter()\n\n useEffect(() => {\n async function preloadRouteChunks() {\n try {\n const postsRoute = router.routesByPath['/posts']\n await Promise.all([\n router.loadRouteChunk(router.routesByPath['/']),\n router.loadRouteChunk(postsRoute),\n router.loadRouteChunk(postsRoute.parentRoute),\n ])\n } catch (err) {\n // Failed to preload route chunk\n }\n }\n\n preloadRouteChunks()\n }, [router])\n\n return <div />\n}\n```\n\n# Render Optimizations\n\nTanStack Router includes several optimizations to ensure your components only re-render when necessary. These optimizations include:\n\n## structural sharing\n\nTanStack Router uses a technique called \"structural sharing\" to preserve as many references as possible between re-renders, which is particularly useful for state stored in the URL, such as search parameters.\n\nFor example, consider a `details` route with two search parameters, `foo` and `bar`, accessed like this:\n\n```tsx\nconst search = Route.useSearch()\n```\n\nWhen only `bar` is changed by navigating from `/details?foo=f1&bar=b1` to `/details?foo=f1&bar=b2`, `search.foo` will be referentially stable and only `search.bar` will be replaced.\n\n## fine-grained selectors\n\nYou can access and subscribe to the router state using various hooks like `useRouterState`, `useSearch`, and others. If you only want a specific component to re-render when a particular subset of the router state such as a subset of the search parameters changes, you can use partial subscriptions with the `select` property.\n\n```tsx\n// component won't re-render when `bar` changes\nconst foo = Route.useSearch({ select: ({ foo }) => foo })\n```\n\n### structural sharing with fine-grained selectors\n\nThe `select` function can perform various calculations on the router state, allowing you to return different types of values, such as objects. For example:\n\n```tsx\nconst result = Route.useSearch({\n select: (search) => {\n return {\n foo: search.foo,\n hello: `hello ${search.foo}`,\n }\n },\n})\n```\n\nAlthough this works, it will cause your component to re-render each time, since `select` is now returning a new object each time it\u2019s called.\n\nYou can avoid this re-rendering issue by using \"structural sharing\" as described above. By default, structural sharing is turned off to maintain backward compatibility, but this may change in v2.\n\nTo enable structural sharing for fine grained selectors, you have two options:\n\n#### Enable it by default in the router options:\n\n```tsx\nconst router = createRouter({\n routeTree,\n defaultStructuralSharing: true,\n})\n```\n\n#### Enable it per hook usage as shown here:\n\n```tsx\nconst result = Route.useSearch({\n select: (search) => {\n return {\n foo: search.foo,\n hello: `hello ${search.foo}`,\n }\n },\n structuralSharing: true,\n})\n```\n\n> [!IMPORTANT]\n> Structural sharing only works with JSON-compatible data. This means you cannot use `select` to return items like class instances if structural sharing is enabled.\n\nIn line with TanStack Router's type-safe design, TypeScript will raise an error if you attempt the following:\n\n```tsx\nconst result = Route.useSearch({\n select: (search) => {\n return {\n date: new Date(),\n }\n },\n structuralSharing: true,\n})\n```\n\nIf structural sharing is enabled by default in the router options, you can prevent this error by setting `structuralSharing: false`.\n\n# Route Masking\n\nRoute masking is a way to mask the actual URL of a route that gets persisted to the browser's history and URL bar. This is useful for scenarios where you want to show a different URL than the one that is actually being navigated to and then falling back to the displayed URL when it is shared and (optionally) when the page is reloaded. Here's a few examples:\n\n- Navigating to a modal route like `/photo/5/modal`, but masking the actual URL as `/photos/5`\n- Navigating to a modal route like `/post/5/comments`, but masking the actual URL as `/posts/5`\n- Navigating to a route with the search param `?showLogin=true`, but masking the URL to _not_ contain the search param\n- Navigating to a route with the search param `?modal=settings`, but masking the URL as `/settings'\n\nEach of these scenarios can be achieved with route masking and even extended to support more advanced patterns like [parallel routes](./parallel-routes.md).\n\n## How does route masking work?\n\n> [!IMPORTANT]\n> You **do not** need to understand how route masking works in order to use it. This section is for those who are curious about how it works under the hood. Skip to [How do I use route masking?](#how-do-i-use-route-masking) to learn how to use it!.\n\nRoute masking utilizes the `location.state` API to store the desired runtime location inside of the location that will get written to the URL. It stores this runtime location under the `__tempLocation` state property:\n\n```tsx\nconst location = {\n pathname: '/photos/5',\n search: '',\n hash: '',\n state: {\n key: 'wesdfs',\n __tempKey: 'sadfasd',\n __tempLocation: {\n pathname: '/photo/5/modal',\n search: '',\n hash: '',\n state: {},\n },\n },\n}\n```\n\nWhen the router parses a location from history with the `location.state.__tempLocation` property, it will use that location instead of the one that was parsed from the URL. This allows you to navigate to a route like `/photos/5` and have the router actually navigate to `/photo/5/modal` instead. When this happens, the history location is saved back into the `location.maskedLocation` property, just in case we need to know what the **actual URL** is. One example of where this is used is in the Devtools where we detect if a route is masked and show the actual URL instead of the masked one!\n\nRemember, you don't need to worry about any of this. It's all handled for you automatically under the hood!\n\n## How do I use route masking?\n\nRoute masking is a simple API that can be used in 2 ways:\n\n- Imperatively via the `mask` option available on the `<Link>` and `navigate()` APIs\n- Declaratively via the Router's `routeMasks` option\n\nWhen using either route masking APIs, the `mask` option accepts the same navigation object that the `<Link>` and `navigate()` APIs accept. This means you can use the same `to`, `replace`, `state`, and `search` options that you're already familiar with. The only difference is that the `mask` option will be used to mask the URL of the route being navigated to.\n\n> \uD83E\uDDE0 The mask option is also **type-safe**! This means that if you're using TypeScript, you'll get type errors if you try to pass an invalid navigation object to the `mask` option. Booyah!\n\n### Imperative route masking\n\nThe `<Link>` and `navigate()` APIs both accept a `mask` option that can be used to mask the URL of the route being navigated to. Here's an example of using it with the `<Link>` component:\n\n```tsx\n<Link\n to=\"/photos/$photoId/modal\"\n params={{ photoId: 5 }}\n mask={{\n to: '/photos/$photoId',\n params: {\n photoId: 5,\n },\n }}\n>\n Open Photo\n</Link>\n```\n\nAnd here's an example of using it with the `navigate()` API:\n\n```tsx\nconst navigate = useNavigate()\n\nfunction onOpenPhoto() {\n navigate({\n to: '/photos/$photoId/modal',\n params: { photoId: 5 },\n mask: {\n to: '/photos/$photoId',\n params: {\n photoId: 5,\n },\n },\n })\n}\n```\n\n### Declarative route masking\n\nIn addition to the imperative API, you can also use the Router's `routeMasks` option to declaratively mask routes. Instead of needing to pass the `mask` option to every `<Link>` or `navigate()` call, you can instead create a route mask on the Router to mask routes that match a certain pattern. Here's an example of the same route mask from above, but using the `routeMasks` option instead:\n\n// Use the following for the example below\n\n```tsx\nimport { createRouteMask } from '@tanstack/react-router'\n\nconst photoModalToPhotoMask = createRouteMask({\n routeTree,\n from: '/photos/$photoId/modal',\n to: '/photos/$photoId',\n params: (prev) => ({\n photoId: prev.photoId,\n }),\n})\n\nconst router = createRouter({\n routeTree,\n routeMasks: [photoModalToPhotoMask],\n})\n```\n\nWhen creating a route mask, you'll need to pass 1 argument with at least:\n\n- `routeTree` - The route tree that the route mask will be applied to\n- `from` - The route ID that the route mask will be applied to\n- `...navigateOptions` - The standard `to`, `search`, `params`, `replace`, etc options that the `<Link>` and `navigate()` APIs accept\n\n> \uD83E\uDDE0 The `createRouteMask` option is also **type-safe**! This means that if you're using TypeScript, you'll get type errors if you try to pass an invalid route mask to the `routeMasks` option.\n\n## Unmasking when sharing the URL\n\nURLs are automatically unmasked when they are shared since as soon as a URL is detached from your browsers local history stack, the URL masking data is no longer available. Essentially, as soon as you copy and paste a URL out of your history, its masking data is lost... after all, that's the point of masking a URL!\n\n## Local Unmasking Defaults\n\n**By default, URLs are not unmasked when the page is reloaded locally**. Masking data is stored in the `location.state` property of the history location, so as long as the history location is still in memory in your history stack, the masking data will be available and the URL will continue to be masked.\n\n## Unmasking on page reload\n\n**As stated above, URLs are not unmasked when the page is reloaded by default**.\n\nIf you want to unmask a URL locally when the page is reloaded, you have 3 options, each overriding the previous one in priority if passed:\n\n- Set the Router's default `unmaskOnReload` option to `true`\n- Return the `unmaskOnReload: true` option from the masking function when creating a route mask with `createRouteMask()`\n- Pass the `unmaskOnReload: true` option to the `<Link`> component or `navigate()` API\n\n# Router Context\n\nTanStack Router's router context is a very powerful tool that can be used for dependency injection among many other things. Aptly named, the router context is passed through the router and down through each matching route. At each route in the hierarchy, the context can be modified or added to. Here's a few ways you might use the router context practically:\n\n- Dependency Injection\n - You can supply dependencies (e.g. a loader function, a data fetching client, a mutation service) which the route and all child routes can access and use without importing or creating directly.\n- Breadcrumbs\n - While the main context object for each route is merged as it descends, each route's unique context is also stored making it possible to attach breadcrumbs or methods to each route's context.\n- Dynamic meta tag management\n - You can attach meta tags to each route's context and then use a meta tag manager to dynamically update the meta tags on the page as the user navigates the site.\n\nThese are just suggested uses of the router context. You can use it for whatever you want!\n\n## Typed Router Context\n\nLike everything else, the root router context is strictly typed. This type can be augmented via any route's `beforeLoad` option as it is merged down the route match tree. To constrain the type of the root router context, you must use the `createRootRouteWithContext<YourContextTypeHere>()(routeOptions)` function to create a new router context instead of the `createRootRoute()` function to create your root route. Here's an example:\n\n```tsx\nimport {\n createRootRouteWithContext,\n createRouter,\n} from '@tanstack/react-router'\n\ninterface MyRouterContext {\n user: User\n}\n\n// Use the routerContext to create your root route\nconst rootRoute = createRootRouteWithContext<MyRouterContext>()({\n component: App,\n})\n\nconst routeTree = rootRoute.addChildren([\n // ...\n])\n\n// Use the routerContext to create your router\nconst router = createRouter({\n routeTree,\n})\n```\n\n> [!TIP]\n> `MyRouterContext` only needs to contain content that will be passed directly to `createRouter` below. All other context added in `beforeLoad` will be inferred.\n\n## Passing the initial Router Context\n\nThe router context is passed to the router at instantiation time. You can pass the initial router context to the router via the `context` option:\n\n> [!TIP]\n> If your context has any required properties, you will see a TypeScript error if you don't pass them in the initial router context. If all of your context properties are optional, you will not see a TypeScript error and passing the context will be optional. If you don't pass a router context, it defaults to `{}`.\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\n// Use the routerContext you created to create your router\nconst router = createRouter({\n routeTree,\n context: {\n user: {\n id: '123',\n name: 'John Doe',\n },\n },\n})\n```\n\n### Invalidating the Router Context\n\nIf you need to invalidate the context state you are passing into the router, you can call the `invalidate` method to tell the router to recompute the context. This is useful when you need to update the context state and have the router recompute the context for all routes.\n\n```tsx\nfunction useAuth() {\n const router = useRouter()\n const [user, setUser] = useState<User | null>(null)\n\n useEffect(() => {\n const unsubscribe = auth.onAuthStateChanged((user) => {\n setUser(user)\n router.invalidate()\n })\n\n return unsubscribe\n }, [])\n\n return user\n}\n```\n\n## Using the Router Context\n\nOnce you have defined the router context type, you can use it in your route definitions:\n\n```tsx\n// src/routes/todos.tsx\nexport const Route = createFileRoute('/todos')({\n component: Todos,\n loader: ({ context }) => fetchTodosByUserId(context.user.id),\n})\n```\n\nYou can even inject data fetching and mutation implementations themselves! In fact, this is highly recommended \uD83D\uDE1C\n\nLet's try this with a simple function to fetch some todos:\n\n```tsx\nconst fetchTodosByUserId = async ({ userId }) => {\n const response = await fetch(`/api/todos?userId=${userId}`)\n const data = await response.json()\n return data\n}\n\nconst router = createRouter({\n routeTree: rootRoute,\n context: {\n userId: '123',\n fetchTodosByUserId,\n },\n})\n```\n\nThen, in your route:\n\n```tsx\n// src/routes/todos.tsx\nexport const Route = createFileRoute('/todos')({\n component: Todos,\n loader: ({ context }) => context.fetchTodosByUserId(context.userId),\n})\n```\n\n### How about an external data fetching library?\n\n```tsx\nimport {\n createRootRouteWithContext,\n createRouter,\n} from '@tanstack/react-router'\n\ninterface MyRouterContext {\n queryClient: QueryClient\n}\n\nconst rootRoute = createRootRouteWithContext<MyRouterContext>()({\n component: App,\n})\n\nconst queryClient = new QueryClient()\n\nconst router = createRouter({\n routeTree: rootRoute,\n context: {\n queryClient,\n },\n})\n```\n\nThen, in your route:\n\n```tsx\n// src/routes/todos.tsx\nexport const Route = createFileRoute('/todos')({\n component: Todos,\n loader: async ({ context }) => {\n await context.queryClient.ensureQueryData({\n queryKey: ['todos', { userId: user.id }],\n queryFn: fetchTodos,\n })\n },\n})\n```\n\n## How about using React Context/Hooks?\n\nWhen trying to use React Context or Hooks in your route's `beforeLoad` or `loader` functions, it's important to remember React's [Rules of Hooks](https://react.dev/reference/rules/rules-of-hooks). You can't use hooks in a non-React function, so you can't use hooks in your `beforeLoad` or `loader` functions.\n\nSo, how do we use React Context or Hooks in our route's `beforeLoad` or `loader` functions? We can use the router context to pass down the React Context or Hooks to our route's `beforeLoad` or `loader` functions.\n\nLet's look at the setup for an example, where we pass down a `useNetworkStrength` hook to our route's `loader` function:\n\n- `src/routes/__root.tsx`\n\n```tsx\n// First, make sure the context for the root route is typed\nimport { createRootRouteWithContext } from '@tanstack/react-router'\nimport { useNetworkStrength } from '@/hooks/useNetworkStrength'\n\ninterface MyRouterContext {\n networkStrength: ReturnType<typeof useNetworkStrength>\n}\n\nexport const Route = createRootRouteWithContext<MyRouterContext>()({\n component: App,\n})\n```\n\nIn this example, we'd instantiate the hook before rendering the router using the `<RouterProvider />`. This way, the hook would be called in React-land, therefore adhering to the Rules of Hooks.\n\n- `src/router.tsx`\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nimport { routeTree } from './routeTree.gen'\n\nexport const router = createRouter({\n routeTree,\n context: {\n networkStrength: undefined!, // We'll set this in React-land\n },\n})\n```\n\n- `src/main.tsx`\n\n```tsx\nimport { RouterProvider } from '@tanstack/react-router'\nimport { router } from './router'\n\nimport { useNetworkStrength } from '@/hooks/useNetworkStrength'\n\nfunction App() {\n const networkStrength = useNetworkStrength()\n // Inject the returned value from the hook into the router context\n return <RouterProvider router={router} context={{ networkStrength }} />\n}\n\n// ...\n```\n\nSo, now in our route's `loader` function, we can access the `networkStrength` hook from the router context:\n\n- `src/routes/posts.tsx`\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts')({\n component: Posts,\n loader: ({ context }) => {\n if (context.networkStrength === 'STRONG') {\n // Do something\n }\n },\n})\n```\n\n## Modifying the Router Context\n\nThe router context is passed down the route tree and is merged at each route. This means that you can modify the context at each route and the modifications will be available to all child routes. Here's an example:\n\n- `src/routes/__root.tsx`\n\n```tsx\nimport { createRootRouteWithContext } from '@tanstack/react-router'\n\ninterface MyRouterContext {\n foo: boolean\n}\n\nexport const Route = createRootRouteWithContext<MyRouterContext>()({\n component: App,\n})\n```\n\n- `src/router.tsx`\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nimport { routeTree } from './routeTree.gen'\n\nconst router = createRouter({\n routeTree,\n context: {\n foo: true,\n },\n})\n```\n\n- `src/routes/todos.tsx`\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/todos')({\n component: Todos,\n beforeLoad: () => {\n return {\n bar: true,\n }\n },\n loader: ({ context }) => {\n context.foo // true\n context.bar // true\n },\n})\n```\n\n## Processing Accumulated Route Context\n\nContext, especially the isolated route `context` objects, make it trivial to accumulate and process the route context objects for all matched routes. Here's an example where we use all of the matched route contexts to generate a breadcrumb trail:\n\n```tsx\n// src/routes/__root.tsx\nexport const Route = createRootRoute({\n component: () => {\n const matches = useRouterState({ select: (s) => s.matches })\n\n const breadcrumbs = matches\n .filter((match) => match.context.getTitle)\n .map(({ pathname, context }) => {\n return {\n title: context.getTitle(),\n path: pathname,\n }\n })\n\n // ...\n },\n})\n```\n\nUsing that same route context, we could also generate a title tag for our page's `<head>`:\n\n```tsx\n// src/routes/__root.tsx\nexport const Route = createRootRoute({\n component: () => {\n const matches = useRouterState({ select: (s) => s.matches })\n\n const matchWithTitle = [...matches]\n .reverse()\n .find((d) => d.context.getTitle)\n\n const title = matchWithTitle?.context.getTitle() || 'My App'\n\n return (\n <html>\n <head>\n <title>{title}</title>\n </head>\n <body>{/* ... */}</body>\n </html>\n )\n },\n})\n```\n\n# Scroll Restoration\n\n## Hash/Top-of-Page Scrolling\n\nOut of the box, TanStack Router supports both **hash scrolling** and **top-of-page scrolling** without any additional configuration.\n\n## Scroll-to-top & Nested Scrollable Areas\n\nBy default, scroll-to-top mimics the behavior of the browser, which means only the `window` itself is scrolled to the top after successful navigation. For many apps however, it's common for the main scrollable area to be a nested div or similar because of advanced layouts. If you would like TanStack Router to also scroll these main scrollable areas for you, you can add selectors to target them using the `routerOptions.scrollToTopSelectors`:\n\n```tsx\nconst router = createRouter({\n scrollToTopSelectors: ['#main-scrollable-area'],\n})\n```\n\nFor complex selectors that cannot be simply resolved using `document.querySelector(selector)`, you can pass functions that return HTML elements to `routerOptions.scrollToTopSelectors`:\n\n```tsx\nconst selector = () =>\n document\n .querySelector('#shadowRootParent')\n ?.shadowRoot?.querySelector('#main-scrollable-area')\n\nconst router = createRouter({\n scrollToTopSelectors: [selector],\n})\n```\n\nThese selectors are handled **in addition to `window`** which cannot be disabled currently.\n\n## Scroll Restoration\n\nScroll restoration is the process of restoring the scroll position of a page when the user navigates back to it. This is normally a built-in feature for standard HTML based websites, but can be difficult to replicate for SPA applications because:\n\n- SPAs typically use the `history.pushState` API for navigation, so the browser doesn't know to restore the scroll position natively\n- SPAs sometimes render content asynchronously, so the browser doesn't know the height of the page until after it's rendered\n- SPAs can sometimes use nested scrollable containers to force specific layouts and features.\n\nNot only that, but it's very common for applications to have multiple scrollable areas within an app, not just the body. For example, a chat application might have a scrollable sidebar and a scrollable chat area. In this case, you would want to restore the scroll position of both areas independently.\n\nTo alleviate this problem, TanStack Router provides a scroll restoration component and hook that handle the process of monitoring, caching and restoring scroll positions for you.\n\nIt does this by:\n\n- Monitoring the DOM for scroll events\n- Registering scrollable areas with the scroll restoration cache\n- Listening to the proper router events to know when to cache and restore scroll positions\n- Storing scroll positions for each scrollable area in the cache (including `window` and `body`)\n- Restoring scroll positions after successful navigations before DOM paint\n\nThat may sound like a lot, but for you, it's as simple as this:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n scrollRestoration: true,\n})\n```\n\n> [!NOTE]\n> The `<ScrollRestoration />` component still works, but has been deprecated.\n\n## Custom Cache Keys\n\nFalling in behind Remix's own Scroll Restoration APIs, you can also customize the key used to cache scroll positions for a given scrollable area using the `getKey` option. This could be used, for example, to force the same scroll position to be used regardless of the users browser history.\n\nThe `getKey` option receives the relevant `Location` state from TanStack Router and expects you to return a string to uniquely identify the scrollable measurements for that state.\n\nThe default `getKey` is `(location) => location.state.__TSR_key!`, where `__TSR_key` is the unique key generated for each entry in the history.\n\n> Older versions, prior to `v1.121.34`, used `state.key` as the default key, but this has been deprecated in favor of `state.__TSR_key`. For now, `location.state.key` will still be available for compatibility, but it will be removed in the next major version.\n\n## Examples\n\nYou could sync scrolling to the pathname:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n getScrollRestorationKey: (location) => location.pathname,\n})\n```\n\nYou can conditionally sync only some paths, then use the key for the rest:\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n getScrollRestorationKey: (location) => {\n const paths = ['/', '/chat']\n return paths.includes(location.pathname)\n ? location.pathname\n : location.state.__TSR_key!\n },\n})\n```\n\n## Preventing Scroll Restoration\n\nSometimes you may want to prevent scroll restoration from happening. To do this you can utilize the `resetScroll` option available on the following APIs:\n\n- `<Link resetScroll={false}>`\n- `navigate({ resetScroll: false })`\n- `redirect({ resetScroll: false })`\n\nWhen `resetScroll` is set to `false`, the scroll position for the next navigation will not be restored (if navigating to an existing history event in the stack) or reset to the top (if it's a new history event in the stack).\n\n## Manual Scroll Restoration\n\nMost of the time, you won't need to do anything special to get scroll restoration to work. However, there are some cases where you may need to manually control scroll restoration. The most common example is **virtualized lists**.\n\nTo manually control scroll restoration for virtualized lists within the whole browser window:\n\n[//]: # 'VirtualizedWindowScrollRestorationExample'\n\n```tsx\nfunction Component() {\n const scrollEntry = useElementScrollRestoration({\n getElement: () => window,\n })\n\n // Let's use TanStack Virtual to virtualize some content!\n const virtualizer = useWindowVirtualizer({\n count: 10000,\n estimateSize: () => 100,\n // We pass the scrollY from the scroll restoration entry to the virtualizer\n // as the initial offset\n initialOffset: scrollEntry?.scrollY,\n })\n\n return (\n <div>\n {virtualizer.getVirtualItems().map(item => (\n ...\n ))}\n </div>\n )\n}\n```\n\n[//]: # 'VirtualizedWindowScrollRestorationExample'\n\nTo manually control scroll restoration for a specific element, you can use the `useElementScrollRestoration` hook and the `data-scroll-restoration-id` DOM attribute:\n\n[//]: # 'ManualRestorationExample'\n\n```tsx\nfunction Component() {\n // We need a unique ID for manual scroll restoration on a specific element\n // It should be as unique as possible for this element across your app\n const scrollRestorationId = 'myVirtualizedContent'\n\n // We use that ID to get the scroll entry for this element\n const scrollEntry = useElementScrollRestoration({\n id: scrollRestorationId,\n })\n\n // Let's use TanStack Virtual to virtualize some content!\n const virtualizerParentRef = React.useRef<HTMLDivElement>(null)\n const virtualizer = useVirtualizer({\n count: 10000,\n getScrollElement: () => virtualizerParentRef.current,\n estimateSize: () => 100,\n // We pass the scrollY from the scroll restoration entry to the virtualizer\n // as the initial offset\n initialOffset: scrollEntry?.scrollY,\n })\n\n return (\n <div\n ref={virtualizerParentRef}\n // We pass the scroll restoration ID to the element\n // as a custom attribute that will get picked up by the\n // scroll restoration watcher\n data-scroll-restoration-id={scrollRestorationId}\n className=\"flex-1 border rounded-lg overflow-auto relative\"\n >\n ...\n </div>\n )\n}\n```\n\n[//]: # 'ManualRestorationExample'\n\n## Scroll Behavior\n\nTo control the scroll behavior when navigating between pages, you can use the `scrollRestorationBehavior` option. This allows you to make the transition between pages instant instead of a smooth scroll. The global configuration of scroll restoration behavior has the same options as those supported by the browser, which are `smooth`, `instant`, and `auto` (see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#behavior) for more information).\n\n```tsx\nimport { createRouter } from '@tanstack/react-router'\n\nconst router = createRouter({\n scrollRestorationBehavior: 'instant',\n})\n```\n\n# Search Params\n\nSimilar to how TanStack Query made handling server-state in your React and Solid applications a breeze, TanStack Router aims to unlock the power of URL search params in your applications.\n\n> \uD83E\uDDE0 If you are on a really old browser, like IE11, you may need to use a polyfill for `URLSearchParams`.\n\n## Why not just use `URLSearchParams`?\n\nWe get it, you've been hearing a lot of \"use the platform\" lately and for the most part, we agree. However, we also believe it's important to recognize where the platform falls short for more advanced use-cases and we believe `URLSearchParams` is one of these circumstances.\n\nTraditional Search Param APIs usually assume a few things:\n\n- Search params are always strings\n- They are _mostly_ flat\n- Serializing and deserializing using `URLSearchParams` is good enough (Spoiler alert: it's not.)\n- Search params modifications are tightly coupled with the URL's pathname and must be updated together, even if the pathname is not changing.\n\nReality is very different from these assumptions though.\n\n- Search params represent application state, so inevitably, we will expect them to have the same DX associated with other state managers. This means having the capability of distinguishing between primitive value types and efficiently storing and manipulating complex data structures like nested arrays and objects.\n- There are many ways to serialize and deserialize state with different tradeoffs. You should be able to choose the best one for your application or at the very least get a better default than `URLSearchParams`.\n- Immutability & Structural Sharing. Every time you stringify and parse url search params, referential integrity and object identity is lost because each new parse creates a brand new data structure with a unique memory reference. If not properly managed over its lifetime, this constant serialization and parsing can result in unexpected and undesirable performance issues, especially in frameworks like React that choose to track reactivity via immutability or in Solid that normally relies on reconciliation to detect changes from deserialized data sources.\n- Search params, while an important part of the URL, do frequently change independently of the URL's pathname. For example, a user may want to change the page number of a paginated list without touching the URL's pathname.\n\n## Search Params, the \"OG\" State Manager\n\nYou've probably seen search params like `?page=3` or `?filter-name=tanner` in the URL. There is no question that this is truly **a form of global state** living inside of the URL. It's valuable to store specific pieces of state in the URL because:\n\n- Users should be able to:\n - Cmd/Ctrl + Click to open a link in a new tab and reliably see the state they expected\n - Bookmark and share links from your application with others with assurances that they will see exactly the state as when the link was copied.\n - Refresh your app or navigate back and forth between pages without losing their state\n- Developers should be able to easily:\n - Add, remove or modify state in the URL with the same great DX as other state managers\n - Easily validate search params coming from the URL in a format and type that is safe for their application to consume\n - Read and write to search params without having to worry about the underlying serialization format\n\n## JSON-first Search Params\n\nTo achieve the above, the first step built in to TanStack Router is a powerful search param parser that automatically converts the search string of your URL to structured JSON. This means that you can store any JSON-serializable data structure in your search params and it will be parsed and serialized as JSON. This is a huge improvement over `URLSearchParams` which has limited support for array-like structures and nested data.\n\nFor example, navigating to the following route:\n\n```tsx\nconst link = (\n <Link\n to=\"/shop\"\n search={{\n pageIndex: 3,\n includeCategories: ['electronics', 'gifts'],\n sortBy: 'price',\n desc: true,\n }}\n />\n)\n```\n\nWill result in the following URL:\n\n```\n/shop?pageIndex=3&includeCategories=%5B%22electronics%22%2C%22gifts%22%5D&sortBy=price&desc=true\n```\n\nWhen this URL is parsed, the search params will be accurately converted back to the following JSON:\n\n```json\n{\n \"pageIndex\": 3,\n \"includeCategories\": [\"electronics\", \"gifts\"],\n \"sortBy\": \"price\",\n \"desc\": true\n}\n```\n\nIf you noticed, there are a few things going on here:\n\n- The first level of the search params is flat and string based, just like `URLSearchParams`.\n- First level values that are not strings are accurately preserved as actual numbers and booleans.\n- Nested data structures are automatically converted to URL-safe JSON strings\n\n> \uD83E\uDDE0 It's common for other tools to assume that search params are always flat and string-based which is why we've chosen to keep things URLSearchParam compliant at the first level. This ultimately means that even though TanStack Router is managing your nested search params as JSON, other tools will still be able to write to the URL and read first-level params normally.\n\n## Validating and Typing Search Params\n\nDespite TanStack Router being able to parse search params into reliable JSON, they ultimately still came from **a user-facing raw-text input**. Similar to other serialization boundaries, this means that before you consume search params, they should be validated into a format that your application can trust and rely on.\n\n### Enter Validation + TypeScript!\n\nTanStack Router provides convenient APIs for validating and typing search params. This all starts with the `Route`'s `validateSearch` option:\n\n```tsx\n// /routes/shop.products.tsx\n\ntype ProductSearchSortOptions = 'newest' | 'oldest' | 'price'\n\ntype ProductSearch = {\n page: number\n filter: string\n sort: ProductSearchSortOptions\n}\n\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: (search: Record<string, unknown>): ProductSearch => {\n // validate and parse the search params into a typed state\n return {\n page: Number(search?.page ?? 1),\n filter: (search.filter as string) || '',\n sort: (search.sort as ProductSearchSortOptions) || 'newest',\n }\n },\n})\n```\n\nIn the above example, we're validating the search params of the `Route` and returning a typed `ProductSearch` object. This typed object is then made available to this route's other options **and any child routes, too!**\n\n### Validating Search Params\n\nThe `validateSearch` option is a function that is provided the JSON parsed (but non-validated) search params as a `Record<string, unknown>` and returns a typed object of your choice. It's usually best to provide sensible fallbacks for malformed or unexpected search params so your users' experience stays non-interrupted.\n\nHere's an example:\n\n```tsx\n// /routes/shop.products.tsx\n\ntype ProductSearchSortOptions = 'newest' | 'oldest' | 'price'\n\ntype ProductSearch = {\n page: number\n filter: string\n sort: ProductSearchSortOptions\n}\n\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: (search: Record<string, unknown>): ProductSearch => {\n // validate and parse the search params into a typed state\n return {\n page: Number(search?.page ?? 1),\n filter: (search.filter as string) || '',\n sort: (search.sort as ProductSearchSortOptions) || 'newest',\n }\n },\n})\n```\n\nHere's an example using the [Zod](https://zod.dev/) library (but feel free to use any validation library you want) to both validate and type the search params in a single step:\n\n```tsx\n// /routes/shop.products.tsx\n\nimport { z } from 'zod'\n\nconst productSearchSchema = z.object({\n page: z.number().catch(1),\n filter: z.string().catch(''),\n sort: z.enum(['newest', 'oldest', 'price']).catch('newest'),\n})\n\ntype ProductSearch = z.infer<typeof productSearchSchema>\n\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: (search) => productSearchSchema.parse(search),\n})\n```\n\nBecause `validateSearch` also accepts an object with the `parse` property, this can be shortened to:\n\n```tsx\nvalidateSearch: productSearchSchema\n```\n\nIn the above example, we used Zod's `.catch()` modifier instead of `.default()` to avoid showing an error to the user because we firmly believe that if a search parameter is malformed, you probably don't want to halt the user's experience through the app to show a big fat error message. That said, there may be times that you **do want to show an error message**. In that case, you can use `.default()` instead of `.catch()`.\n\nThe underlying mechanics why this works relies on the `validateSearch` function throwing an error. If an error is thrown, the route's `onError` option will be triggered (and `error.routerCode` will be set to `VALIDATE_SEARCH` and the `errorComponent` will be rendered instead of the route's `component` where you can handle the search param error however you'd like.\n\n#### Adapters\n\nWhen using a library like [Zod](https://zod.dev/) to validate search params you might want to `transform` search params before committing the search params to the URL. A common `zod` `transform` is `default` for example.\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { z } from 'zod'\n\nconst productSearchSchema = z.object({\n page: z.number().default(1),\n filter: z.string().default(''),\n sort: z.enum(['newest', 'oldest', 'price']).default('newest'),\n})\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: productSearchSchema,\n})\n```\n\nIt might be surprising that when you try to navigate to this route, `search` is required. The following `Link` will type error as `search` is missing.\n\n```tsx\n<Link to=\"/shop/products\" />\n```\n\nFor validation libraries we recommend using adapters which infer the correct `input` and `output` types.\n\n### Zod\n\nAn adapter is provided for [Zod](https://zod.dev/) which will pipe through the correct `input` type and `output` type\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { zodValidator } from '@tanstack/zod-adapter'\nimport { z } from 'zod'\n\nconst productSearchSchema = z.object({\n page: z.number().default(1),\n filter: z.string().default(''),\n sort: z.enum(['newest', 'oldest', 'price']).default('newest'),\n})\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: zodValidator(productSearchSchema),\n})\n```\n\nThe important part here is the following use of `Link` no longer requires `search` params\n\n```tsx\n<Link to=\"/shop/products\" />\n```\n\nHowever the use of `catch` here overrides the types and makes `page`, `filter` and `sort` `unknown` causing type loss. We have handled this case by providing a `fallback` generic function which retains the types but provides a `fallback` value when validation fails\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { fallback, zodValidator } from '@tanstack/zod-adapter'\nimport { z } from 'zod'\n\nconst productSearchSchema = z.object({\n page: fallback(z.number(), 1).default(1),\n filter: fallback(z.string(), '').default(''),\n sort: fallback(z.enum(['newest', 'oldest', 'price']), 'newest').default(\n 'newest',\n ),\n})\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: zodValidator(productSearchSchema),\n})\n```\n\nTherefore when navigating to this route, `search` is optional and retains the correct types.\n\nWhile not recommended, it is also possible to configure `input` and `output` type in case the `output` type is more accurate than the `input` type\n\n```tsx\nconst productSearchSchema = z.object({\n page: fallback(z.number(), 1).default(1),\n filter: fallback(z.string(), '').default(''),\n sort: fallback(z.enum(['newest', 'oldest', 'price']), 'newest').default(\n 'newest',\n ),\n})\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: zodValidator({\n schema: productSearchSchema,\n input: 'output',\n output: 'input',\n }),\n})\n```\n\nThis provides flexibility in which type you want to infer for navigation and which types you want to infer for reading search params.\n\n### Valibot\n\n> [!WARNING]\n> Router expects the valibot 1.0 package to be installed.\n\nWhen using [Valibot](https://valibot.dev/) an adapter is not needed to ensure the correct `input` and `output` types are used for navigation and reading search params. This is because `valibot` implements [Standard Schema](https://github.com/standard-schema/standard-schema)\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport * as v from 'valibot'\n\nconst productSearchSchema = v.object({\n page: v.optional(v.fallback(v.number(), 1), 1),\n filter: v.optional(v.fallback(v.string(), ''), ''),\n sort: v.optional(\n v.fallback(v.picklist(['newest', 'oldest', 'price']), 'newest'),\n 'newest',\n ),\n})\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: productSearchSchema,\n})\n```\n\n### Arktype\n\n> [!WARNING]\n> Router expects the arktype 2.0-rc package to be installed.\n\nWhen using [ArkType](https://arktype.io/) an adapter is not needed to ensure the correct `input` and `output` types are used for navigation and reading search params. This is because [ArkType](https://arktype.io/) implements [Standard Schema](https://github.com/standard-schema/standard-schema)\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { type } from 'arktype'\n\nconst productSearchSchema = type({\n page: 'number = 1',\n filter: 'string = \"\"',\n sort: '\"newest\" | \"oldest\" | \"price\" = \"newest\"',\n})\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: productSearchSchema,\n})\n```\n\n### Effect/Schema\n\nWhen using [Effect/Schema](https://effect.website/docs/schema/introduction/) an adapter is not needed to ensure the correct `input` and `output` types are used for navigation and reading search params. This is because [Effect/Schema](https://effect.website/docs/schema/standard-schema/) implements [Standard Schema](https://github.com/standard-schema/standard-schema)\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\nimport { Schema as S } from 'effect'\n\nconst productSearchSchema = S.standardSchemaV1(\n S.Struct({\n page: S.NumberFromString.pipe(\n S.optional,\n S.withDefaults({\n constructor: () => 1,\n decoding: () => 1,\n }),\n ),\n filter: S.String.pipe(\n S.optional,\n S.withDefaults({\n constructor: () => '',\n decoding: () => '',\n }),\n ),\n sort: S.Literal('newest', 'oldest', 'price').pipe(\n S.optional,\n S.withDefaults({\n constructor: () => 'newest' as const,\n decoding: () => 'newest' as const,\n }),\n ),\n }),\n)\n\nexport const Route = createFileRoute('/shop/products/')({\n validateSearch: productSearchSchema,\n})\n```\n\n## Reading Search Params\n\nOnce your search params have been validated and typed, you're finally ready to start reading and writing to them. There are a few ways to do this in TanStack Router, so let's check them out.\n\n### Using Search Params in Loaders\n\nPlease read the [Search Params in Loaders](./data-loading.md#using-loaderdeps-to-access-search-params) section for more information about how to read search params in loaders with the `loaderDeps` option.\n\n### Search Params are inherited from Parent Routes\n\nThe search parameters and types of parents are merged as you go down the route tree, so child routes also have access to their parent's search params:\n\n- `shop.products.tsx`\n\n```tsx\nconst productSearchSchema = z.object({\n page: z.number().catch(1),\n filter: z.string().catch(''),\n sort: z.enum(['newest', 'oldest', 'price']).catch('newest'),\n})\n\ntype ProductSearch = z.infer<typeof productSearchSchema>\n\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: productSearchSchema,\n})\n```\n\n- `shop.products.$productId.tsx`\n\n```tsx\nexport const Route = createFileRoute('/shop/products/$productId')({\n beforeLoad: ({ search }) => {\n search\n // ^? ProductSearch \u2705\n },\n})\n```\n\n### Search Params in Components\n\nYou can access your route's validated search params in your route's `component` via the `useSearch` hook.\n\n```tsx\n// /routes/shop.products.tsx\n\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: productSearchSchema,\n})\n\nconst ProductList = () => {\n const { page, filter, sort } = Route.useSearch()\n\n return <div>...</div>\n}\n```\n\n> [!TIP]\n> If your component is code-split, you can use the [getRouteApi function](./code-splitting.md#manually-accessing-route-apis-in-other-files-with-the-getrouteapi-helper) to avoid having to import the `Route` configuration to get access to the typed `useSearch()` hook.\n\n### Search Params outside of Route Components\n\nYou can access your route's validated search params anywhere in your app using the `useSearch` hook. By passing the `from` id/path of your origin route, you'll get even better type safety:\n\n```tsx\n// /routes/shop.products.tsx\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: productSearchSchema,\n // ...\n})\n\n// Somewhere else...\n\n// /components/product-list-sidebar.tsx\nconst routeApi = getRouteApi('/shop/products')\n\nconst ProductList = () => {\n const routeSearch = routeApi.useSearch()\n\n // OR\n\n const { page, filter, sort } = useSearch({\n from: Route.fullPath,\n })\n\n return <div>...</div>\n}\n```\n\nOr, you can loosen up the type-safety and get an optional `search` object by passing `strict: false`:\n\n```tsx\nfunction ProductList() {\n const search = useSearch({\n strict: false,\n })\n // {\n // page: number | undefined\n // filter: string | undefined\n // sort: 'newest' | 'oldest' | 'price' | undefined\n // }\n\n return <div>...</div>\n}\n```\n\n## Writing Search Params\n\nNow that you've learned how to read your route's search params, you'll be happy to know that you've already seen the primary APIs to modify and update them. Let's remind ourselves a bit\n\n### `<Link search />`\n\nThe best way to update search params is to use the `search` prop on the `<Link />` component.\n\nIf the search for the current page shall be updated and the `from` prop is specified, the `to` prop can be omitted. \nHere's an example:\n\n```tsx\n// /routes/shop.products.tsx\nexport const Route = createFileRoute('/shop/products')({\n validateSearch: productSearchSchema,\n})\n\nconst ProductList = () => {\n return (\n <div>\n <Link from={Route.fullPath} search={(prev) => ({ page: prev.page + 1 })}>\n Next Page\n </Link>\n </div>\n )\n}\n```\n\nIf you want to update the search params in a generic component that is rendered on multiple routes, specifying `from` can be challenging.\n\nIn this scenario you can set `to=\".\"` which will give you access to loosely typed search params. \nHere is an example that illustrates this:\n\n```tsx\n// `page` is a search param that is defined in the __root route and hence available on all routes.\nconst PageSelector = () => {\n return (\n <div>\n <Link to=\".\" search={(prev) => ({ ...prev, page: prev.page + 1 })}>\n Next Page\n </Link>\n </div>\n )\n}\n```\n\nIf the generic component is only rendered in a specific subtree of the route tree, you can specify that subtree using `from`. Here you can omit `to='.'` if you want.\n\n```tsx\n// `page` is a search param that is defined in the /posts route and hence available on all of its child routes.\nconst PageSelector = () => {\n return (\n <div>\n <Link\n from=\"/posts\"\n to=\".\"\n search={(prev) => ({ ...prev, page: prev.page + 1 })}\n >\n Next Page\n </Link>\n </div>\n )\n```\n\n### `useNavigate(), navigate({ search })`\n\nThe `navigate` function also accepts a `search` option that works the same way as the `search` prop on `<Link />`:\n\n```tsx\n// /routes/shop.products.tsx\nexport const Route = createFileRoute('/shop/products/$productId')({\n validateSearch: productSearchSchema,\n})\n\nconst ProductList = () => {\n const navigate = useNavigate({ from: Route.fullPath })\n\n return (\n <div>\n <button\n onClick={() => {\n navigate({\n search: (prev) => ({ page: prev.page + 1 }),\n })\n }}\n >\n Next Page\n </button>\n </div>\n )\n}\n```\n\n### `router.navigate({ search })`\n\nThe `router.navigate` function works exactly the same way as the `useNavigate`/`navigate` hook/function above.\n\n### `<Navigate search />`\n\nThe `<Navigate search />` component works exactly the same way as the `useNavigate`/`navigate` hook/function above, but accepts its options as props instead of a function argument.\n\n## Transforming search with search middlewares\n\nWhen link hrefs are built, by default the only thing that matters for the query string part is the `search` property of a `<Link>`.\n\nTanStack Router provides a way to manipulate search params before the href is generated via **search middlewares**.\nSearch middlewares are functions that transform the search parameters when generating new links for a route or its descendants.\nThey are also executed upon navigation after search validation to allow manipulation of the query string.\n\nThe following example shows how to make sure that for **every** link that is being built, the `rootValue` search param is added _if_ it is part of the current search params. If a link specifies `rootValue` inside `search`, then that value is used for building the link.\n\n```tsx\nimport { z } from 'zod'\nimport { createFileRoute } from '@tanstack/react-router'\nimport { zodValidator } from '@tanstack/zod-adapter'\n\nconst searchSchema = z.object({\n rootValue: z.string().optional(),\n})\n\nexport const Route = createRootRoute({\n validateSearch: zodValidator(searchSchema),\n search: {\n middlewares: [\n ({ search, next }) => {\n const result = next(search)\n return {\n rootValue: search.rootValue,\n ...result,\n }\n },\n ],\n },\n})\n```\n\nSince this specific use case is quite common, TanStack Router provides a generic implementation to retain search params via `retainSearchParams`:\n\n```tsx\nimport { z } from 'zod'\nimport { createFileRoute, retainSearchParams } from '@tanstack/react-router'\nimport { zodValidator } from '@tanstack/zod-adapter'\n\nconst searchSchema = z.object({\n rootValue: z.string().optional(),\n})\n\nexport const Route = createRootRoute({\n validateSearch: zodValidator(searchSchema),\n search: {\n middlewares: [retainSearchParams(['rootValue'])],\n },\n})\n```\n\nAnother common use case is to strip out search params from links if their default value is set. TanStack Router provides a generic implementation for this use case via `stripSearchParams`:\n\n```tsx\nimport { z } from 'zod'\nimport { createFileRoute, stripSearchParams } from '@tanstack/react-router'\nimport { zodValidator } from '@tanstack/zod-adapter'\n\nconst defaultValues = {\n one: 'abc',\n two: 'xyz',\n}\n\nconst searchSchema = z.object({\n one: z.string().default(defaultValues.one),\n two: z.string().default(defaultValues.two),\n})\n\nexport const Route = createFileRoute('/hello')({\n validateSearch: zodValidator(searchSchema),\n search: {\n // strip default values\n middlewares: [stripSearchParams(defaultValues)],\n },\n})\n```\n\nMultiple middlewares can be chained. The following example shows how to combine both `retainSearchParams` and `stripSearchParams`.\n\n```tsx\nimport {\n Link,\n createFileRoute,\n retainSearchParams,\n stripSearchParams,\n} from '@tanstack/react-router'\nimport { z } from 'zod'\nimport { zodValidator } from '@tanstack/zod-adapter'\n\nconst defaultValues = ['foo', 'bar']\n\nexport const Route = createFileRoute('/search')({\n validateSearch: zodValidator(\n z.object({\n retainMe: z.string().optional(),\n arrayWithDefaults: z.string().array().default(defaultValues),\n required: z.string(),\n }),\n ),\n search: {\n middlewares: [\n retainSearchParams(['retainMe']),\n stripSearchParams({ arrayWithDefaults: defaultValues }),\n ],\n },\n})\n```\n\n# SSR\n\n> [!WARNING]\n> While every effort has been made to separate these APIs from changes to Tanstack Start, there are underlying shared implementations internally. Therefore these can be subject to change and should be regarded as experimental until Start reaches stable status.\n\nServer Side Rendering (SSR) is the process of rendering a component on the server and sending the HTML markup to the client. The client then hydrates the markup into a fully interactive component.\n\nThere are usually two different flavors of SSR to be considered:\n\n- Non-streaming SSR\n - The entire page is rendered on the server and sent to the client in one single HTML request, including the serialized data the application needs to hydrate on the client.\n- Streaming SSR\n - The critical first paint of the page is rendered on the server and sent to the client in one single HTML request, including the serialized data the application needs to hydrate on the client\n - The rest of the page is then streamed to the client as it is rendered on the server.\n\nThis guide will explain how to implement both flavors of SSR with TanStack Router!\n\n## Non-Streaming SSR\n\nNon-Streaming server-side rendering is the classic process of rendering the markup for your entire application page on the server and sending the completed HTML markup (and data) to the client. The client then hydrates the markup into a fully interactive application again.\n\nTo implement non-streaming SSR with TanStack Router, you will need the following utilities:\n\n- `RouterClient` from `@tanstack/react-router`\n - e.g. `<RouterClient router={router} />`\n - Rendering this component in your client entry will render your application and also automatically implement the `Wrap` component option on `Router`\n- And, either:\n - `defaultRenderHandler` from `@tanstack/react-router`\n - This will render your application in your server entry and also automatically handle application-level hydration/dehydration and also automatically implement the RouterServer component.\n or:\n - `renderRouterToString` from `@tanstack/react-router`\n - This differs from defaultRenderHandler in that it allows you to manually specify the `Wrap` component option on `Router` together with any other providers you may need to wrap it with.\n - `RouterServer` from `@tanstack/react-router`\n - This implements the `Wrap` component option on `Router`\n\n### Automatic Server History\n\nOn the client, Router defaults to using an instance of `createBrowserHistory`, which is the preferred type of history to use on the client. On the server, however, you will want to use an instance of `createMemoryHistory` instead. This is because `createBrowserHistory` uses the `window` object, which does not exist on the server. This is handled automatically for you in the RouterServer component.\n\n### Automatic Loader Dehydration/Hydration\n\nResolved loader data fetched by routes is automatically dehydrated and rehydrated by TanStack Router so long as you complete the standard SSR steps outlined in this guide.\n\n\u26A0\uFE0F If you are using deferred data streaming, you will also need to ensure that you have implemented the [SSR Streaming & Stream Transform](#streaming-ssr) pattern near the end of this guide.\n\nFor more information on how to utilize data loading, see the [Data Loading](./data-loading.md) guide.\n\n### Router Creation\n\nSince your router will exist both on the server and the client, it's important that you create your router in a way that is consistent between both of these environments. The easiest way to do this is to expose a `createRouter` function in a shared file that can be imported and called by both your server and client entry files.\n\n```tsx\n// src/router.tsx\nimport { createRouter as createTanstackRouter } from '@tanstack/react-router'\nimport { routeTree } from './routeTree.gen'\n\nexport function createRouter() {\n return createTanstackRouter({ routeTree })\n}\n\ndeclare module '@tanstack/react-router' {\n interface Register {\n router: ReturnType<typeof createRouter>\n }\n}\n```\n\n### Rendering the Application on the Server\n\nNow that you have a router instance that has loaded all the critical data for the current URL, you can render your application on the server:\n\nusing `defaultRenderHandler`\n\n```tsx\n// src/entry-server.tsx\nimport {\n createRequestHandler,\n defaultRenderToString,\n} from '@tanstack/react-router/ssr/server'\nimport { createRouter } from './router'\n\nexport async function render({ request }: { request: Request }) {\n const handler = createRequestHandler({ request, createRouter })\n\n return await handler(defaultRenderHandler)\n}\n```\n\nusing `renderRouterToString`\n\n```tsx\n// src/entry-server.tsx\nimport {\n createRequestHandler,\n renderRouterToString,\n RouterServer,\n} from '@tanstack/react-router/ssr/server'\nimport { createRouter } from './router'\n\nexport function render({ request }: { request: Request }) {\n const handler = createRequestHandler({ request, createRouter })\n\n return handler(({ request, responseHeaders, router }) =>\n renderRouterToString({\n request,\n responseHeaders,\n router,\n children: <RouterServer router={router} />,\n }),\n )\n}\n```\n\nNOTE: The createRequestHandler method requires a web api standard Request object, while the handler method will return a web api standard Response promise.\n\nShould you be using a server framework like Express that uses its own Request and Response objects you would need to convert from the one to the other. Please have a look at the examples for how such an implementation might look like.\n\n## Rendering the Application on the Client\n\nOn the client, things are much simpler.\n\n- Create your router instance\n- Render your application using the `<RouterClient />` component\n\n[//]: # 'ClientEntryFileExample'\n\n```tsx\n// src/entry-client.tsx\nimport { hydrateRoot } from 'react-dom/client'\nimport { RouterClient } from '@tanstack/react-router/ssr/client'\nimport { createRouter } from './router'\n\nconst router = createRouter()\n\nhydrateRoot(document, <RouterClient router={router} />)\n```\n\n[//]: # 'ClientEntryFileExample'\n\nWith this setup, your application will be rendered on the server and then hydrated on the client!\n\n## Streaming SSR\n\nStreaming SSR is the most modern flavor of SSR and is the process of continuously and incrementally sending HTML markup to the client as it is rendered on the server. This is slightly different from traditional SSR in concept because beyond being able to dehydrate and rehydrate a critical first paint, markup and data with lower priority or slower response times can be streamed to the client after the initial render, but in the same request.\n\nThis pattern can be useful for pages that have slow or high-latency data fetching requirements. For example, if you have a page that needs to fetch data from a third-party API, you can stream the critical initial markup and data to the client and then stream the less-critical third-party data to the client as it is resolved.\n\n> [!NOTE]\n> This streaming pattern is all automatic as long as you are using either `defaultStreamHandler` or `renderRouterToStream`.\n\nusing `defaultStreamHandler`\n\n```tsx\n// src/entry-server.tsx\nimport {\n createRequestHandler,\n defaultStreamHandler,\n} from '@tanstack/react-router/ssr/server'\nimport { createRouter } from './router'\n\nexport async function render({ request }: { request: Request }) {\n const handler = createRequestHandler({ request, createRouter })\n\n return await handler(defaultStreamHandler)\n}\n```\n\nusing `renderRouterToStream`\n\n```tsx\n// src/entry-server.tsx\nimport {\n createRequestHandler,\n renderRouterToStream,\n RouterServer,\n} from '@tanstack/react-router/ssr/server'\nimport { createRouter } from './router'\n\nexport function render({ request }: { request: Request }) {\n const handler = createRequestHandler({ request, createRouter })\n\n return handler(({ request, responseHeaders, router }) =>\n renderRouterToStream({\n request,\n responseHeaders,\n router,\n children: <RouterServer router={router} />,\n }),\n )\n}\n```\n\n## Streaming Dehydration/Hydration\n\nStreaming dehydration/hydration is an advanced pattern that goes beyond markup and allows you to dehydrate and stream any supporting data from the server to the client and rehydrate it on arrival. This is useful for applications that may need to further use/manage the underlying data that was used to render the initial markup on the server.\n\n## Data Serialization\n\nWhen using SSR, data passed between the server and the client must be serialized before it is sent across network-boundaries. TanStack Router handles this serialization using a very lightweight serializer that supports common data types beyond JSON.stringify/JSON.parse.\n\nOut of the box, the following types are supported:\n\n- `undefined`\n- `Date`\n- `Error`\n- `FormData`\n\nIf you feel that there are other types that should be supported by default, please open an issue on the TanStack Router repository.\n\nIf you are using more complex data types like `Map`, `Set`, `BigInt`, etc, you may need to use a custom serializer to ensure that your type-definitions are accurate and your data is correctly serialized and deserialized. We are currently working on both a more robust serializer and a way to customize the serializer for your application. Open an issue if you are interested in helping out!\n\n# Static Route Data\n\nWhen creating routes, you can optionally specify a `staticData` property in the route's options. This object can literally contain anything you want as long as it's synchronously available when you create your route.\n\nIn addition to being able to access this data from the route itself, you can also access it from any match under the `match.staticData` property.\n\n## Example\n\n- `posts.tsx`\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts')({\n staticData: {\n customData: 'Hello!',\n },\n})\n```\n\nYou can then access this data anywhere you have access to your routes, including matches that can be mapped back to their routes.\n\n- `__root.tsx`\n\n```tsx\nimport { createRootRoute } from '@tanstack/react-router'\n\nexport const Route = createRootRoute({\n component: () => {\n const matches = useMatches()\n\n return (\n <div>\n {matches.map((match) => {\n return <div key={match.id}>{match.staticData.customData}</div>\n })}\n </div>\n )\n },\n})\n```\n\n## Enforcing Static Data\n\nIf you want to enforce that a route has static data, you can use declaration merging to add a type to the route's static option:\n\n```tsx\ndeclare module '@tanstack/react-router' {\n interface StaticDataRouteOption {\n customData: string\n }\n}\n```\n\nNow, if you try to create a route without the `customData` property, you'll get a type error:\n\n```tsx\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/posts')({\n staticData: {\n // Property 'customData' is missing in type '{ customData: number; }' but required in type 'StaticDataRouteOption'.ts(2741)\n },\n})\n```\n\n## Optional Static Data\n\nIf you want to make static data optional, simply add a `?` to the property:\n\n```tsx\ndeclare module '@tanstack/react-router' {\n interface StaticDataRouteOption {\n customData?: string\n }\n}\n```\n\nAs long as there are any required properties on the `StaticDataRouteOption`, you'll be required to pass in an object.\n\n# Type Safety\n\nTanStack Router is built to be as type-safe as possible within the limits of the TypeScript compiler and runtime. This means that it's not only written in TypeScript, but that it also **fully infers the types it's provided and tenaciously pipes them through the entire routing experience**.\n\nUltimately, this means that you write **less types as a developer** and have **more confidence in your code** as it evolves.\n\n## Route Definitions\n\n### File-based Routing\n\nRoutes are hierarchical, and so are their definitions. If you're using file-based routing, much of the type-safety is already taken care of for you.\n\n### Code-based Routing\n\nIf you're using the `Route` class directly, you'll need to be aware of how to ensure your routes are typed properly using the `Route`'s `getParentRoute` option. This is because child routes need to be aware of **all** of their parent routes types. Without this, those precious search params you parsed out of your _layout_ and _pathless layout_ routes, 3 levels up, would be lost to the JS void.\n\nSo, don't forget to pass the parent route to your child routes!\n\n```tsx\nconst parentRoute = createRoute({\n getParentRoute: () => parentRoute,\n})\n```\n\n## Exported Hooks, Components, and Utilities\n\nFor the types of your router to work with top-level exports like `Link`, `useNavigate`, `useParams`, etc. they must permeate the TypeScript module boundary and be registered right into the library. To do this, we use declaration merging on the exported `Register` interface.\n\n```ts\nconst router = createRouter({\n // ...\n})\n\ndeclare module '@tanstack/react-router' {\n interface Register {\n router: typeof router\n }\n}\n```\n\nBy registering your router with the module, you can now use the exported hooks, components, and utilities with your router's exact types.\n\n## Fixing the Component Context Problem\n\nComponent context is a wonderful tool in React and other frameworks for providing dependencies to components. However, if that context is changing types as it moves throughout your component hierarchy, it becomes impossible for TypeScript to know how to infer those changes. To get around this, context-based hooks and components require that you give them a hint on how and where they are being used.\n\n```tsx\nexport const Route = createFileRoute('/posts')({\n component: PostsComponent,\n})\n\nfunction PostsComponent() {\n // Each route has type-safe versions of most of the built-in hooks from TanStack Router\n const params = Route.useParams()\n const search = Route.useSearch()\n\n // Some hooks require context from the *entire* router, not just the current route. To achieve type-safety here,\n // we must pass the `from` param to tell the hook our relative position in the route hierarchy.\n const navigate = useNavigate({ from: Route.fullPath })\n // ... etc\n}\n```\n\nEvery hook and component that requires a context hint will have a `from` param where you can pass the ID or path of the route you are rendering within.\n\n> \uD83E\uDDE0 Quick tip: If your component is code-split, you can use the [getRouteApi function](./code-splitting.md#manually-accessing-route-apis-in-other-files-with-the-getrouteapi-helper) to avoid having to pass in the `Route.fullPath` to get access to the typed `useParams()` and `useSearch()` hooks.\n\n### What if I don't know the route? What if it's a shared component?\n\nThe `from` property is optional, which means if you don't pass it, you'll get the router's best guess on what types will be available. Usually, that means you'll get a union of all of the types of all of the routes in the router.\n\n### What if I pass the wrong `from` path?\n\nIt's technically possible to pass a `from` that satisfies TypeScript, but may not match the actual route you are rendering within at runtime. In this case, each hook and component that supports `from` will detect if your expectations don't match the actual route you are rendering within, and will throw a runtime error.\n\n### What if I don't know the route, or it's a shared component, and I can't pass `from`?\n\nIf you are rendering a component that is shared across multiple routes, or you are rendering a component that is not within a route, you can pass `strict: false` instead of a `from` option. This will not only silence the runtime error, but will also give you relaxed, but accurate types for the potential hook you are calling. A good example of this is calling `useSearch` from a shared component:\n\n```tsx\nfunction MyComponent() {\n const search = useSearch({ strict: false })\n}\n```\n\nIn this case, the `search` variable will be typed as a union of all possible search params from all routes in the router.\n\n## Router Context\n\nRouter context is so extremely useful as it's the ultimate hierarchical dependency injection. You can supply context to the router and to each and every route it renders. As you build up this context, TanStack Router will merge it down with the hierarchy of routes, so that each route has access to the context of all of its parents.\n\nThe `createRootRouteWithContext` factory creates a new router with the instantiated type, which then creates a requirement for you to fulfill the same type contract to your router, and will also ensure that your context is properly typed throughout the entire route tree.\n\n```tsx\nconst rootRoute = createRootRouteWithContext<{ whateverYouWant: true }>()({\n component: App,\n})\n\nconst routeTree = rootRoute.addChildren([\n // ... all child routes will have access to `whateverYouWant` in their context\n])\n\nconst router = createRouter({\n routeTree,\n context: {\n // This will be required to be passed now\n whateverYouWant: true,\n },\n})\n```\n\n## Performance Recommendations\n\nAs your application scales, TypeScript check times will naturally increase. There are a few things to keep in mind when your application scales to keep your TS check times down.\n\n### Only infer types you need\n\nA great pattern with client side data caches (TanStack Query, etc.) is to prefetch data. For example with TanStack Query you might have a route which calls `queryClient.ensureQueryData` in a `loader`.\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId/deep')({\n loader: ({ context: { queryClient }, params: { postId } }) =>\n queryClient.ensureQueryData(postQueryOptions(postId)),\n component: PostDeepComponent,\n})\n\nfunction PostDeepComponent() {\n const params = Route.useParams()\n const data = useSuspenseQuery(postQueryOptions(params.postId))\n\n return <></>\n}\n```\n\nThis may look fine and for small route trees and you may not notice any TS performance issues. However in this case TS has to infer the loader's return type, despite it never being used in your route. If the loader data is a complex type with many routes that prefetch in this manner, it can slow down editor performance. In this case, the change is quite simple and let typescript infer Promise<void>.\n\n```tsx\nexport const Route = createFileRoute('/posts/$postId/deep')({\n loader: async ({ context: { queryClient }, params: { postId } }) => {\n await queryClient.ensureQueryData(postQueryOptions(postId))\n },\n component: PostDeepComponent,\n})\n\nfunction PostDeepComponent() {\n const params = Route.useParams()\n const data = useSuspenseQuery(postQueryOptions(params.postId))\n\n return <></>\n}\n```\n\nThis way the loader data is never inferred and it moves the inference out of the route tree to the first time you use `useSuspenseQuery`.\n\n### Narrow to relevant routes as much as you possibly can\n\nConsider the following usage of `Link`\n\n```tsx\n<Link to=\"..\" search={{ page: 0 }} />\n<Link to=\".\" search={{ page: 0 }} />\n```\n\n**These examples are bad for TS performance**. That's because `search` resolves to a union of all `search` params for all routes and TS has to check whatever you pass to the `search` prop against this potentially big union. As your application grows, this check time will increase linearly to number of routes and search params. We have done our best to optimize for this case (TypeScript will typically do this work once and cache it) but the initial check against this large union is expensive. This also applies to `params` and other API's such as `useSearch`, `useParams`, `useNavigate` etc.\n\nInstead you should try to narrow to relevant routes with `from` or `to`.\n\n```tsx\n<Link from={Route.fullPath} to=\"..\" search={{page: 0}} />\n<Link from=\"/posts\" to=\"..\" search={{page: 0}} />\n```\n\nRemember you can always pass a union to `to` or `from` to narrow the routes you're interested in.\n\n```tsx\nconst from: '/posts/$postId/deep' | '/posts/' = '/posts/'\n<Link from={from} to='..' />\n```\n\nYou can also pass branches to `from` to only resolve `search` or `params` to be from any descendants of that branch:\n\n```tsx\nconst from = '/posts'\n<Link from={from} to='..' />\n```\n\n`/posts` could be a branch with many descendants which share the same `search` or `params`\n\n### Consider using the object syntax of `addChildren`\n\nIt's typical of routes to have `params` `search`, `loaders` or `context` that can even reference external dependencies which are also heavy on TS inference. For such applications, using objects for creating the route tree can be more performant than tuples.\n\n`createChildren` also can accept an object. For large route trees with complex routes and external libraries, objects can be much faster for TS to type check as opposed to large tuples. The performance gains depend on your project, what external dependencies you have and how the types for those libraries are written\n\n```tsx\nconst routeTree = rootRoute.addChildren({\n postsRoute: postsRoute.addChildren({ postRoute, postsIndexRoute }),\n indexRoute,\n})\n```\n\nNote this syntax is more verbose but has better TS performance. With file based routing, the route tree is generated for you so a verbose route tree is not a concern\n\n### Avoid internal types without narrowing\n\nIt's common you might want to re-use types exposed. For example you might be tempted to use `LinkProps` like so\n\n```tsx\nconst props: LinkProps = {\n to: '/posts/',\n}\n\nreturn (\n <Link {...props}>\n)\n```\n\n**This is VERY bad for TS Performance**. The problem here is `LinkProps` has no type arguments and is therefore an extremely large type. It includes `search` which is a union of all `search` params, it contains `params` which is a union of all `params`. When merging this object with `Link` it will do a structural comparison of this huge type.\n\nInstead you can use `as const satisfies` to infer a precise type and not `LinkProps` directly to avoid the huge check\n\n```tsx\nconst props = {\n to: '/posts/',\n} as const satisfies LinkProps\n\nreturn (\n <Link {...props}>\n)\n```\n\nAs `props` is not of type `LinkProps` and therefore this check is cheaper because the type is much more precise. You can also improve type checking further by narrowing `LinkProps`\n\n```tsx\nconst props = {\n to: '/posts/',\n} as const satisfies LinkProps<RegisteredRouter, string '/posts/'>\n\nreturn (\n <Link {...props}>\n)\n```\n\nThis is even faster as we're checking against the narrowed `LinkProps` type.\n\nYou can also use this to narrow the type of `LinkProps` to a specific type to be used as a prop or parameter to a function\n\n```tsx\nexport const myLinkProps = [\n {\n to: '/posts',\n },\n {\n to: '/posts/$postId',\n params: { postId: 'postId' },\n },\n] as const satisfies ReadonlyArray<LinkProps>\n\nexport type MyLinkProps = (typeof myLinkProps)[number]\n\nconst MyComponent = (props: { linkProps: MyLinkProps }) => {\n return <Link {...props.linkProps} />\n}\n```\n\nThis is faster than using `LinkProps` directly in a component because `MyLinkProps` is a much more precise type\n\nAnother solution is not to use `LinkProps` and to provide inversion of control to render a `Link` component narrowed to a specific route. Render props are a good method of inverting control to the user of a component\n\n```tsx\nexport interface MyComponentProps {\n readonly renderLink: () => React.ReactNode\n}\n\nconst MyComponent = (props: MyComponentProps) => {\n return <div>{props.renderLink()}</div>\n}\n\nconst Page = () => {\n return <MyComponent renderLink={() => <Link to=\"/absolute\" />} />\n}\n```\n\nThis particular example is very fast as we've inverted control of where we're navigating to the user of the component. The `Link` is narrowed to the exact route\nwe want to navigate to\n\n# Type Utilities\n\nMost types exposed by TanStack Router are internal, subject to breaking changes and not always easy to use. That is why TanStack Router has a subset of exposed types focused on ease of use with the intension to be used externally. These types provide the same type safe experience from TanStack Router's runtime concepts on the type level, with flexibility of where to provide type checking\n\n## Type checking Link options with `ValidateLinkOptions`\n\n`ValidateLinkOptions` type checks object literal types to ensure they conform to `Link` options at inference sites. For example, you may have a generic `HeadingLink` component which accepts a `title` prop along with `linkOptions`, the idea being this component can be re-used for any navigation.\n\n```tsx\nexport interface HeaderLinkProps<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TOptions = unknown,\n> {\n title: string\n linkOptions: ValidateLinkOptions<TRouter, TOptions>\n}\n\nexport function HeadingLink<TRouter extends RegisteredRouter, TOptions>(\n props: HeaderLinkProps<TRouter, TOptions>,\n): React.ReactNode\nexport function HeadingLink(props: HeaderLinkProps): React.ReactNode {\n return (\n <>\n <h1>{props.title}</h1>\n <Link {...props.linkOptions} />\n </>\n )\n}\n```\n\nA more permissive overload of `HeadingLink` is used to avoid type assertions you would otherwise have to do with the generic signature. Using a looser signature without type parameters is an easy way to avoid type assertions in the implementation of `HeadingLink`\n\nAll type parameters for utilities are optional but for the best TypeScript performance `TRouter` should always be specified for the public facing signature. And `TOptions` should always be used at inference sites like `HeadingLink` to infer the `linkOptions` to correctly narrow `params` and `search`\n\nThe result of this is that `linkOptions` in the following is completely type-safe\n\n```tsx\n<HeadingLink title=\"Posts\" linkOptions={{ to: '/posts' }} />\n<HeadingLink title=\"Post\" linkOptions={{ to: '/posts/$postId', params: {postId: 'postId'} }} />\n```\n\n## Type checking an array of Link options with `ValidateLinkOptionsArray`\n\nAll navigation type utilities have an array variant. `ValidateLinkOptionsArray` enables type checking of an array of `Link` options. For example, you might have a generic `Menu` component where each item is a `Link`.\n\n```tsx\nexport interface MenuProps<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TItems extends ReadonlyArray<unknown> = ReadonlyArray<unknown>,\n> {\n items: ValidateLinkOptionsArray<TRouter, TItems>\n}\n\nexport function Menu<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TItems extends ReadonlyArray<unknown>,\n>(props: MenuProps<TRouter, TItems>): React.ReactNode\nexport function Menu(props: MenuProps): React.ReactNode {\n return (\n <ul>\n {props.items.map((item) => (\n <li>\n <Link {...item} />\n </li>\n ))}\n </ul>\n )\n}\n```\n\nThis of course allows the following `items` prop to be completely type-safe\n\n```tsx\n<Menu\n items={[\n { to: '/posts' },\n { to: '/posts/$postId', params: { postId: 'postId' } },\n ]}\n/>\n```\n\nIt is also possible to fix `from` for each `Link` options in the array. This would allow all `Menu` items to navigate relative to `from`. Additional type checking of `from` can be provided by the `ValidateFromPath` utility\n\n```tsx\nexport interface MenuProps<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TItems extends ReadonlyArray<unknown> = ReadonlyArray<unknown>,\n TFrom extends string = string,\n> {\n from: ValidateFromPath<TRouter, TFrom>\n items: ValidateLinkOptionsArray<TRouter, TItems, TFrom>\n}\n\nexport function Menu<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TItems extends ReadonlyArray<unknown>,\n TFrom extends string = string,\n>(props: MenuProps<TRouter, TItems, TFrom>): React.ReactNode\nexport function Menu(props: MenuProps): React.ReactNode {\n return (\n <ul>\n {props.items.map((item) => (\n <li>\n <Link {...item} from={props.from} />\n </li>\n ))}\n </ul>\n )\n}\n```\n\n`ValidateLinkOptionsArray` allows you to fix `from` by providing an extra type parameter. The result is a type safe array of `Link` options providing navigation relative to `from`\n\n```tsx\n<Menu\n from=\"/posts\"\n items={[{ to: '.' }, { to: './$postId', params: { postId: 'postId' } }]}\n/>\n```\n\n## Type checking redirect options with `ValidateRedirectOptions`\n\n`ValidateRedirectOptions` type checks object literal types to ensure they conform to redirect options at inference sites. For example, you may need a generic `fetchOrRedirect` function which accepts a `url` along with `redirectOptions`, the idea being this function will redirect when the `fetch` fails.\n\n```tsx\nexport async function fetchOrRedirect<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TOptions,\n>(\n url: string,\n redirectOptions: ValidateRedirectOptions<TRouter, TOptions>,\n): Promise<unknown>\nexport async function fetchOrRedirect(\n url: string,\n redirectOptions: ValidateRedirectOptions,\n): Promise<unknown> {\n const response = await fetch(url)\n\n if (!response.ok && response.status === 401) {\n throw redirect(redirectOptions)\n }\n\n return await response.json()\n}\n```\n\nThe result is that `redirectOptions` passed to `fetchOrRedirect` is completely type-safe\n\n```tsx\nfetchOrRedirect('http://example.com/', { to: '/login' })\n```\n\n## Type checking navigate options with `ValidateNavigateOptions`\n\n`ValidateNavigateOptions` type checks object literal types to ensure they conform to navigate options at inference sites. For example, you may want to write a custom hook to enable/disable navigation.\n\n[//]: # 'TypeCheckingNavigateOptionsWithValidateNavigateOptionsImpl'\n\n```tsx\nexport interface UseConditionalNavigateResult {\n enable: () => void\n disable: () => void\n navigate: () => void\n}\n\nexport function useConditionalNavigate<\n TRouter extends RegisteredRouter = RegisteredRouter,\n TOptions,\n>(\n navigateOptions: ValidateNavigateOptions<TRouter, TOptions>,\n): UseConditionalNavigateResult\nexport function useConditionalNavigate(\n navigateOptions: ValidateNavigateOptions,\n): UseConditionalNavigateResult {\n const [enabled, setEnabled] = useState(false)\n const navigate = useNavigate()\n return {\n enable: () => setEnabled(true),\n disable: () => setEnabled(false),\n navigate: () => {\n if (enabled) {\n navigate(navigateOptions)\n }\n },\n }\n}\n```\n\n[//]: # 'TypeCheckingNavigateOptionsWithValidateNavigateOptionsImpl'\n\nThe result of this is that `navigateOptions` passed to `useConditionalNavigate` is completely type-safe and we can enable/disable navigation based on react state\n\n```tsx\nconst { enable, disable, navigate } = useConditionalNavigate({\n to: '/posts/$postId',\n params: { postId: 'postId' },\n})\n```\n\n";
2
2
  export default _default;