Repository: TanStack/router
Pull request #2203 (2024-08-27 21:19:08)

feat(router-generator): allow to customize `index` and `route` token

nx-cloud[bot]: # ☁️ Nx Cloud Report

CI is running for commit c5c49b70d0c83e693b4476497251a175e44f310e.

[📂 Click to track the progress, see the status, the terminal output, and the build insights.](https://cloud.nx.app/cipes/66ce42de4f3e8224f8aa1087?utm_source=pull-request&utm_medium=comment)


---

Sent with 💌 from [NxCloud.](https://nx.app?utm_source=pull-request&utm_medium=comment)
pkg-pr-new[bot]: 
_commit: <a href="https://github.com/TanStack/router/runs/29507895165"><code>3dbc242</code></a>_


<details><summary><b>@tanstack/history</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/history@2203
```

</p></details>
      
    

<details><summary><b>@tanstack/react-cross-context</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/react-cross-context@2203
```

</p></details>
      
    

<details><summary><b>@tanstack/react-router</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/react-router@2203
```

</p></details>
      
    

<details><summary><b>@tanstack/react-router-with-query</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/react-router-with-query@2203
```

</p></details>
      
    

<details><summary><b>@tanstack/router-arktype-adapter</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-arktype-adapter@2203
```

</p></details>
      
    

<details><summary><b>@tanstack/router-cli</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-cli@2203
```

</p></details>
      
    

<details><summary><b>@tanstack/router-devtools</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-devtools@2203
```

</p></details>
      
    

<details><summary><b>@tanstack/router-generator</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-generator@2203
```

</p></details>
      
    

<details><summary><b>@tanstack/router-plugin</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-plugin@2203
```

</p></details>
      
    

<details><summary><b>@tanstack/router-valibot-adapter</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-valibot-adapter@2203
```

</p></details>
      
    

<details><summary><b>@tanstack/router-vite-plugin</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-vite-plugin@2203
```

</p></details>
      
    

<details><summary><b>@tanstack/router-zod-adapter</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/router-zod-adapter@2203
```

</p></details>
      
    

<details><summary><b>@tanstack/start</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/start@2203
```

</p></details>
      
    

<details><summary><b>@tanstack/start-vite-plugin</b></summary><p>

```
pnpm add https://pkg.pr.new/@tanstack/start-vite-plugin@2203
```

</p></details>
      
    

[Open in Stackblitz](https://pkg.pr.new/template/e915eecc-31e3-416a-8358-5c7806c54875)
<details><summary><b>More templates</b></summary><p>

- [tanstack-router-react-example-authenticated-routes](https://pkg.pr.new/template/2cb34798-8666-4bca-8096-c2a27d3cbd20)
- [tanstack-router-react-example-basic](https://pkg.pr.new/template/a841b819-9746-4795-9cc3-cf2867e65769)
- [tanstack-router-react-example-basic-default-search-params](https://pkg.pr.new/template/57c05b3e-be3b-4962-aa98-4155aa46f3ef)
- [tanstack-router-react-example-basic-file-based](https://pkg.pr.new/template/96eb8220-2403-4ae3-8799-dc6e5fd91db3)
- [tanstack-router-react-example-basic-file-based-codesplitting](https://pkg.pr.new/template/8dc6a238-2948-43ed-8b39-5b61ceb0efd6)
- [tanstack-router-react-example-react-query](https://pkg.pr.new/template/0ca3cc3f-df5c-48e6-8dda-1bec84b38ff3)
- [tanstack-router-react-example-basic-react-query-file-based](https://pkg.pr.new/template/e6c91f22-389a-4d74-a3ed-47511b6df574)
- [tanstack-router-react-example-basic-ssr-file-based](https://pkg.pr.new/template/4f76331b-7570-49fa-a816-224c5927865d)
- [tanstack-router-react-example-basic-ssr-streaming-file-based](https://pkg.pr.new/template/65846be4-a6ef-40ff-9baa-377e98a569d4)
- [tanstack-router-react-example-deferred-data](https://pkg.pr.new/template/4a0c8281-6beb-4d9c-81cb-3600dc0defa1)
- [tanstack-router-react-example-kitchen-sink](https://pkg.pr.new/template/43c0ea8e-f30a-4d44-80eb-9a5afd2a9a95)
- [tanstack-router-react-example-kitchen-sink-file-based](https://pkg.pr.new/template/fd29a4e2-602f-4bab-ad1d-30f1969359c6)
- [tanstack-router-react-example-kitchen-sink-react-query](https://pkg.pr.new/template/f9f9083f-ec91-4ce5-9591-ed8d6a87be74)
- [tanstack-router-react-example-kitchen-sink-react-query-file-based](https://pkg.pr.new/template/61fc8cb8-040b-45e0-a4ad-c604b3cfa8d5)
- [tanstack-router-react-example-large-file-based](https://pkg.pr.new/template/6313995d-0edf-4c7c-8a2b-c9e0c84b0945)
- [tanstack-router-react-example-location-masking](https://pkg.pr.new/template/7d579ea9-b140-466b-9a91-9254cbe09bc6)
- [tanstack-router-react-example-navigation-blocking](https://pkg.pr.new/template/d881c3e2-3cd5-48a6-a7d6-bc95d8a561fd)
- [tanstack-router-react-example-quickstart](https://pkg.pr.new/template/42e7e367-b585-4140-a41a-4cb22a3446df)
- [tanstack-router-react-example-quickstart-file-based](https://pkg.pr.new/template/d86add39-01b8-4fe0-916f-b49551438e37)
- [tanstack-router-react-example-quickstart-rspack-file-based](https://pkg.pr.new/template/65cf595c-06a1-47d0-9228-60fb084ee93c)
- [tanstack-router-react-example-quickstart-webpack-file-based](https://pkg.pr.new/template/7255e69a-c771-43d2-be83-57632eec2ba7)
- [tanstack-router-react-example-scroll-restoration](https://pkg.pr.new/template/ff2de88f-54a7-4cf6-8d10-ac515854d3d7)
- [tanstack-router-search-validator-adapters](https://pkg.pr.new/template/16e1abbd-66a4-4d0b-b4f2-da5c3bad7c6e)
- [tanstack-router-example-react-start-basic](https://pkg.pr.new/template/234ed35f-299c-4e43-ad49-de3e328141fd)
- [tanstack-router-example-react-start-basic-auth](https://pkg.pr.new/template/c7ac7a66-c9e0-4657-9c5d-4c654405dc6f)
- [tanstack-router-example-react-start-basic-counter](https://pkg.pr.new/template/17b0aa96-6852-4c9a-9baf-8f8662b083eb)
- [tanstack-router-example-react-start-basic-react-query](https://pkg.pr.new/template/75e816a3-ce06-4bad-b2f9-6df45b63be0d)
- [tanstack-router-example-react-start-basic-rsc](https://pkg.pr.new/template/ae02d37c-6cf4-4f52-a69c-e9a905c6fed9)
- [tanstack-router-example-react-start-clerk-basic](https://pkg.pr.new/template/6b224064-a2fb-4d28-bd86-48e4731b5317)
- [tanstack-router-example-react-start-trello-trellaux](https://pkg.pr.new/template/39bf6cf1-9c01-4094-a7df-c47812d39c03)
- [tanstack-router-example-react-start-trellaux](https://pkg.pr.new/template/abc52b6d-7cc2-41dd-8e19-64368a5d4796)
- [tanstack-router-react-example-with-framer-motion](https://pkg.pr.new/template/74097dc8-e2ea-4c80-9ae8-0612b64fcdb8)
- [tanstack-router-react-example-with-trpc](https://pkg.pr.new/template/ba35b8ee-6ca9-4ac9-be0f-6ea2c60d21b0)
- [tanstack-router-react-example-with-trpc-react-query](https://pkg.pr.new/template/cfe2f35d-b72d-498d-b996-e70e7fcc4009)

</p></details>
      
    

schiller-manuel: I need to test but I think underscore prefix does not cause an issue since index/route tokens are replaced before we parse the route name
SeanCassiere: > I need to test but I think underscore prefix does not cause an issue since index/route tokens are replaced before we parse the route name

Definitely something worth adding a test for since the `routePath` replacement currently happens after the layout route status has been determined.

Patch:
diff --git a/docs/framework/react/guide/file-based-routing.md b/docs/framework/react/guide/file-based-routing.md
index a54037493..ac93d9ec5 100644
--- a/docs/framework/react/guide/file-based-routing.md
+++ b/docs/framework/react/guide/file-based-routing.md
@@ -132,9 +132,11 @@ File-based routing requires that you follow a few simple file naming conventions
 - **`(folder)` folder name pattern**:
   - A folder that matches this pattern is treated as a **route group** which prevents this folder to be included in the route's URL path.
 - **`index` Token**
-  - Routes segments ending with the `index` token (but before any file types) will be used to match the parent route when the URL pathname matches the parent route exactly.
+  - Routes segments ending with the `index` token (but before any file types) will be used to match the parent route when the URL pathname matches the parent route exactly.  
+    This can be configured via the `indexToken` configuration option, see [options](#options).
 - **`.route.tsx` File Type**
-  - When using directories to organize your routes, the `route` suffix can be used to create a route file at the directory's path. For example, `blog.post.route.tsx` or `blog/post/route.tsx` can be used at the route file for the `/blog/post` route.
+  - When using directories to organize your routes, the `route` suffix can be used to create a route file at the directory's path. For example, `blog.post.route.tsx` or `blog/post/route.tsx` can be used at the route file for the `/blog/post` route.  
+    This can be configured via the `routeToken` configuration option, see [options](#options).
 - **`.lazy.tsx` File Type**
   - The `lazy` suffix can be used to code-split components for a route. For example, `blog.post.lazy.tsx` will be used as the component for the `blog.post` route.
 
@@ -331,6 +333,10 @@ The following options are available for configuration via the `tsr.config.json`
   - (Optional, **Defaults to `-`**) Route files and directories that start with this string will be ignored. By default this is set to `-` to allow for the use of directories to house related files that do not contain any route files.
 - **`routeFileIgnorePattern`**
   - (Optional) Ignore specific files and directories in the route directory. It can be used in regular expression format. For example, `.((css|const).ts)|test-page` will ignore files / directories with names containing `.css.ts`, `.const.ts` or `test-page`.
+- **`indexToken`**
+  - (Optional, **Defaults to `'index'`**) allows to customize the `index` Token [file naming convention](#file-naming-conventions).
+- **`routeToken`**
+  - (Optional, **Defaults to `'route'`**) allows to customize the `route` Token [file naming convention](#file-naming-conventions).
 - **`routesDirectory`**
   - (Required) The directory containing the routes relative to the cwd.
 - **`generatedRouteTree`**
diff --git a/docs/framework/react/overview.md b/docs/framework/react/overview.md
index dcf38f8eb..b20be5d07 100644
--- a/docs/framework/react/overview.md
+++ b/docs/framework/react/overview.md
@@ -53,7 +53,6 @@ TanStack Router delivers on the same fundamental expectations as other routers t
 - URL Path Params
 - Error Boundaries and Handling
 - SSR
-- Prefetching
 - Route Masking
 
 And it also delivers some new features that raise the bar:
diff --git a/examples/react/authenticated-routes/package.json b/examples/react/authenticated-routes/package.json
index d374cac8c..12dffe9f0 100644
--- a/examples/react/authenticated-routes/package.json
+++ b/examples/react/authenticated-routes/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
     "immer": "^10.1.1",
     "react": "^18.2.0",
diff --git a/examples/react/basic-default-search-params/package.json b/examples/react/basic-default-search-params/package.json
index dfd6ee2ea..83aafaefd 100644
--- a/examples/react/basic-default-search-params/package.json
+++ b/examples/react/basic-default-search-params/package.json
@@ -10,8 +10,8 @@
   },
   "dependencies": {
     "@tanstack/react-query": "^5.51.21",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "redaxios": "^0.5.1",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
diff --git a/examples/react/basic-file-based-codesplitting/package.json b/examples/react/basic-file-based-codesplitting/package.json
index 4a474babd..0892c49d4 100644
--- a/examples/react/basic-file-based-codesplitting/package.json
+++ b/examples/react/basic-file-based-codesplitting/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
     "immer": "^10.1.1",
     "react": "^18.2.0",
diff --git a/examples/react/basic-file-based/package.json b/examples/react/basic-file-based/package.json
index 2db906486..c8d0abe66 100644
--- a/examples/react/basic-file-based/package.json
+++ b/examples/react/basic-file-based/package.json
@@ -10,8 +10,8 @@
     "test:e2e": "playwright test --project=chromium"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
     "immer": "^10.1.1",
     "react": "^18.2.0",
diff --git a/examples/react/basic-react-query-file-based/package.json b/examples/react/basic-react-query-file-based/package.json
index 1bc1b9d9c..f9cbf5f7c 100644
--- a/examples/react/basic-react-query-file-based/package.json
+++ b/examples/react/basic-react-query-file-based/package.json
@@ -12,8 +12,8 @@
   "dependencies": {
     "@tanstack/react-query": "^5.51.21",
     "@tanstack/react-query-devtools": "^5.51.21",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
     "immer": "^10.1.1",
     "react": "^18.2.0",
diff --git a/examples/react/basic-react-query/package.json b/examples/react/basic-react-query/package.json
index 6789d6d8f..789b4306c 100644
--- a/examples/react/basic-react-query/package.json
+++ b/examples/react/basic-react-query/package.json
@@ -12,8 +12,8 @@
   "dependencies": {
     "@tanstack/react-query": "^5.51.21",
     "@tanstack/react-query-devtools": "^5.51.21",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "redaxios": "^0.5.1"
diff --git a/examples/react/basic-ssr-file-based/package.json b/examples/react/basic-ssr-file-based/package.json
index cd1822e68..0ecae8038 100644
--- a/examples/react/basic-ssr-file-based/package.json
+++ b/examples/react/basic-ssr-file-based/package.json
@@ -11,10 +11,10 @@
     "debug": "node --inspect-brk server"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
-    "@tanstack/start": "^1.51.7",
+    "@tanstack/start": "^1.51.9",
     "get-port": "^7.1.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
diff --git a/examples/react/basic-ssr-streaming-file-based/package.json b/examples/react/basic-ssr-streaming-file-based/package.json
index 725406c7f..54b5c49c2 100644
--- a/examples/react/basic-ssr-streaming-file-based/package.json
+++ b/examples/react/basic-ssr-streaming-file-based/package.json
@@ -11,10 +11,10 @@
     "debug": "node --inspect-brk server"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
-    "@tanstack/start": "^1.51.7",
+    "@tanstack/start": "^1.51.9",
     "get-port": "^7.1.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
diff --git a/examples/react/basic/package.json b/examples/react/basic/package.json
index f016d7d04..f81fa46a3 100644
--- a/examples/react/basic/package.json
+++ b/examples/react/basic/package.json
@@ -10,8 +10,8 @@
     "test:e2e": "playwright test --project=chromium"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "redaxios": "^0.5.1"
diff --git a/examples/react/deferred-data/package.json b/examples/react/deferred-data/package.json
index f36a11d71..822ad8633 100644
--- a/examples/react/deferred-data/package.json
+++ b/examples/react/deferred-data/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "redaxios": "^0.5.1",
     "immer": "^10.1.1",
     "react": "^18.2.0",
diff --git a/examples/react/kitchen-sink-file-based/package.json b/examples/react/kitchen-sink-file-based/package.json
index 0b5e6447c..0bfa5d8ca 100644
--- a/examples/react/kitchen-sink-file-based/package.json
+++ b/examples/react/kitchen-sink-file-based/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
     "immer": "^10.1.1",
     "react": "^18.2.0",
diff --git a/examples/react/kitchen-sink-react-query-file-based/package.json b/examples/react/kitchen-sink-react-query-file-based/package.json
index ac0af3053..63044af86 100644
--- a/examples/react/kitchen-sink-react-query-file-based/package.json
+++ b/examples/react/kitchen-sink-react-query-file-based/package.json
@@ -11,8 +11,8 @@
   "dependencies": {
     "@tanstack/react-query": "^5.51.21",
     "@tanstack/react-query-devtools": "^5.51.21",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
     "immer": "^10.1.1",
     "react": "^18.2.0",
diff --git a/examples/react/kitchen-sink-react-query/package.json b/examples/react/kitchen-sink-react-query/package.json
index 4e815e62f..efdfadb29 100644
--- a/examples/react/kitchen-sink-react-query/package.json
+++ b/examples/react/kitchen-sink-react-query/package.json
@@ -11,8 +11,8 @@
   "dependencies": {
     "@tanstack/react-query": "^5.51.21",
     "@tanstack/react-query-devtools": "^5.51.21",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "redaxios": "^0.5.1",
     "immer": "^10.1.1",
     "react": "^18.2.0",
diff --git a/examples/react/kitchen-sink/package.json b/examples/react/kitchen-sink/package.json
index b37761fc3..291a7d635 100644
--- a/examples/react/kitchen-sink/package.json
+++ b/examples/react/kitchen-sink/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "redaxios": "^0.5.1",
     "immer": "^10.1.1",
     "react": "^18.2.0",
diff --git a/examples/react/large-file-based/package.json b/examples/react/large-file-based/package.json
index 9dbe1ebf1..bdfa98cb6 100644
--- a/examples/react/large-file-based/package.json
+++ b/examples/react/large-file-based/package.json
@@ -12,8 +12,8 @@
   },
   "dependencies": {
     "@tanstack/react-query": "^5.51.21",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
     "immer": "^10.1.1",
     "react": "^18.2.0",
diff --git a/examples/react/location-masking/package.json b/examples/react/location-masking/package.json
index 1805664e1..b94e1e350 100644
--- a/examples/react/location-masking/package.json
+++ b/examples/react/location-masking/package.json
@@ -11,8 +11,8 @@
   "dependencies": {
     "@radix-ui/react-dialog": "^1.1.1",
     "@tanstack/react-query": "^5.51.21",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "redaxios": "^0.5.1",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
diff --git a/examples/react/navigation-blocking/package.json b/examples/react/navigation-blocking/package.json
index af91387bf..338f716c2 100644
--- a/examples/react/navigation-blocking/package.json
+++ b/examples/react/navigation-blocking/package.json
@@ -10,8 +10,8 @@
   },
   "dependencies": {
     "@tanstack/react-query": "^5.51.21",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "redaxios": "^0.5.1",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
diff --git a/examples/react/quickstart-file-based/package.json b/examples/react/quickstart-file-based/package.json
index 6e40b3f3d..a58df31ab 100644
--- a/examples/react/quickstart-file-based/package.json
+++ b/examples/react/quickstart-file-based/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
     "immer": "^10.1.1",
     "react": "^18.2.0",
diff --git a/examples/react/quickstart-rspack-file-based/package.json b/examples/react/quickstart-rspack-file-based/package.json
index 4e4c7e729..c4e374c20 100644
--- a/examples/react/quickstart-rspack-file-based/package.json
+++ b/examples/react/quickstart-rspack-file-based/package.json
@@ -8,8 +8,8 @@
     "preview": "rsbuild preview"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "react": "^18.3.1",
     "react-dom": "^18.3.1"
   },
diff --git a/examples/react/quickstart-webpack-file-based/package.json b/examples/react/quickstart-webpack-file-based/package.json
index a2300caab..5662fa9f1 100644
--- a/examples/react/quickstart-webpack-file-based/package.json
+++ b/examples/react/quickstart-webpack-file-based/package.json
@@ -7,8 +7,8 @@
     "build": "webpack build"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "react": "^18.3.1",
     "react-dom": "^18.3.1"
   },
diff --git a/examples/react/quickstart/package.json b/examples/react/quickstart/package.json
index 0b1a3353e..74e0f693f 100644
--- a/examples/react/quickstart/package.json
+++ b/examples/react/quickstart/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
   },
diff --git a/examples/react/scroll-restoration/package.json b/examples/react/scroll-restoration/package.json
index 84c57f05e..2cbe2d523 100644
--- a/examples/react/scroll-restoration/package.json
+++ b/examples/react/scroll-restoration/package.json
@@ -9,9 +9,9 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
     "@tanstack/react-virtual": "^3.8.4",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/router-devtools": "^1.51.9",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
   },
diff --git a/examples/react/search-validator-adapters/package.json b/examples/react/search-validator-adapters/package.json
index d530b99d6..7bff705bc 100644
--- a/examples/react/search-validator-adapters/package.json
+++ b/examples/react/search-validator-adapters/package.json
@@ -9,12 +9,12 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
-    "@tanstack/router-zod-adapter": "^1.51.7",
-    "@tanstack/router-valibot-adapter": "^1.51.7",
-    "@tanstack/router-arktype-adapter": "^1.51.7",
+    "@tanstack/router-zod-adapter": "^1.51.9",
+    "@tanstack/router-valibot-adapter": "^1.51.9",
+    "@tanstack/router-arktype-adapter": "^1.51.9",
     "@tanstack/react-query": "^5.51.21",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
diff --git a/examples/react/start-basic-auth/package.json b/examples/react/start-basic-auth/package.json
index f7dee3b72..8ee073a80 100644
--- a/examples/react/start-basic-auth/package.json
+++ b/examples/react/start-basic-auth/package.json
@@ -14,10 +14,10 @@
   },
   "dependencies": {
     "@prisma/client": "5.17.0",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
-    "@tanstack/start": "^1.51.7",
+    "@tanstack/start": "^1.51.9",
     "@vitejs/plugin-react": "^4.3.1",
     "dotenv": "^16.4.5",
     "isbot": "^5.1.12",
diff --git a/examples/react/start-basic-counter/package.json b/examples/react/start-basic-counter/package.json
index 4e9a5ed63..1bc309e45 100644
--- a/examples/react/start-basic-counter/package.json
+++ b/examples/react/start-basic-counter/package.json
@@ -11,8 +11,8 @@
     "format": "prettier --write '**/*' --ignore-unknown"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/start": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/start": "^1.51.9",
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
     "vinxi": "0.4.2"
diff --git a/examples/react/start-basic-react-query/package.json b/examples/react/start-basic-react-query/package.json
index c6ebed41c..106622cb5 100644
--- a/examples/react/start-basic-react-query/package.json
+++ b/examples/react/start-basic-react-query/package.json
@@ -14,11 +14,11 @@
   "dependencies": {
     "@tanstack/react-query": "^5.51.21",
     "@tanstack/react-query-devtools": "^5.51.21",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/react-router-with-query": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/react-router-with-query": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
-    "@tanstack/start": "^1.51.7",
+    "@tanstack/start": "^1.51.9",
     "@vitejs/plugin-react": "^4.3.1",
     "isbot": "^5.1.14",
     "react": "^18.3.1",
diff --git a/examples/react/start-basic-rsc/package.json b/examples/react/start-basic-rsc/package.json
index 465c4f647..8918415ee 100644
--- a/examples/react/start-basic-rsc/package.json
+++ b/examples/react/start-basic-rsc/package.json
@@ -12,10 +12,10 @@
   },
   "dependencies": {
     "@babel/plugin-syntax-typescript": "^7.24.7",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
-    "@tanstack/start": "^1.51.7",
+    "@tanstack/start": "^1.51.9",
     "redaxios": "^0.5.1",
     "tailwind-merge": "^2.5.2",
     "vinxi": "0.4.2"
diff --git a/examples/react/start-basic/package.json b/examples/react/start-basic/package.json
index d9ddda570..9ad3064a9 100644
--- a/examples/react/start-basic/package.json
+++ b/examples/react/start-basic/package.json
@@ -12,10 +12,10 @@
     "test:e2e": "playwright test --project=chromium"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
-    "@tanstack/start": "^1.51.7",
+    "@tanstack/start": "^1.51.9",
     "@vitejs/plugin-react": "^4.3.1",
     "isbot": "^5.1.14",
     "react": "^18.3.1",
diff --git a/examples/react/start-clerk-basic/package.json b/examples/react/start-clerk-basic/package.json
index d8b908b5e..0116987a3 100644
--- a/examples/react/start-clerk-basic/package.json
+++ b/examples/react/start-clerk-basic/package.json
@@ -13,10 +13,10 @@
   },
   "dependencies": {
     "@clerk/tanstack-start": "0.3.0-snapshot.vdf04997",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
-    "@tanstack/start": "^1.51.7",
+    "@tanstack/start": "^1.51.9",
     "@vitejs/plugin-react": "^4.3.1",
     "dotenv": "^16.4.5",
     "isbot": "^5.1.12",
diff --git a/examples/react/start-convex-trellaux/package.json b/examples/react/start-convex-trellaux/package.json
index 30736eeef..ce4345c7c 100644
--- a/examples/react/start-convex-trellaux/package.json
+++ b/examples/react/start-convex-trellaux/package.json
@@ -15,11 +15,11 @@
   "dependencies": {
     "@tanstack/react-query": "^5.51.21",
     "@tanstack/react-query-devtools": "^5.51.21",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/react-router-with-query": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/react-router-with-query": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
-    "@tanstack/start": "^1.51.7",
+    "@tanstack/start": "^1.51.9",
     "@vitejs/plugin-react": "^4.3.1",
     "@convex-dev/react-query": "0.0.0-alpha.5",
     "concurrently": "^8.2.2",
diff --git a/examples/react/start-trellaux/package.json b/examples/react/start-trellaux/package.json
index 32695825a..91ba52c87 100644
--- a/examples/react/start-trellaux/package.json
+++ b/examples/react/start-trellaux/package.json
@@ -13,11 +13,11 @@
   "dependencies": {
     "@tanstack/react-query": "^5.51.21",
     "@tanstack/react-query-devtools": "^5.51.21",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/react-router-with-query": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/react-router-with-query": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
-    "@tanstack/start": "^1.51.7",
+    "@tanstack/start": "^1.51.9",
     "@vitejs/plugin-react": "^4.3.1",
     "isbot": "^5.1.14",
     "ky": "^1.5.0",
diff --git a/examples/react/with-framer-motion/package.json b/examples/react/with-framer-motion/package.json
index 096cbef76..a2be92e4a 100644
--- a/examples/react/with-framer-motion/package.json
+++ b/examples/react/with-framer-motion/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "redaxios": "^0.5.1",
     "framer-motion": "^11.3.21",
     "immer": "^10.1.1",
diff --git a/examples/react/with-trpc-react-query/package.json b/examples/react/with-trpc-react-query/package.json
index a113af0eb..7e0516609 100644
--- a/examples/react/with-trpc-react-query/package.json
+++ b/examples/react/with-trpc-react-query/package.json
@@ -10,8 +10,8 @@
   "dependencies": {
     "@tanstack/react-query": "^5.51.21",
     "@tanstack/react-query-devtools": "^5.51.21",
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
     "@trpc/client": "11.0.0-rc.477",
     "@trpc/react-query": "11.0.0-rc.477",
diff --git a/examples/react/with-trpc/package.json b/examples/react/with-trpc/package.json
index ba3b61d6c..37f936574 100644
--- a/examples/react/with-trpc/package.json
+++ b/examples/react/with-trpc/package.json
@@ -8,8 +8,8 @@
     "start": "vinxi start"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.51.7",
-    "@tanstack/router-devtools": "^1.51.7",
+    "@tanstack/react-router": "^1.51.9",
+    "@tanstack/router-devtools": "^1.51.9",
     "@tanstack/router-plugin": "^1.51.6",
     "@trpc/client": "11.0.0-rc.477",
     "@trpc/server": "11.0.0-rc.477",
diff --git a/packages/react-router-with-query/package.json b/packages/react-router-with-query/package.json
index 20f15fd1d..d2a01da3a 100644
--- a/packages/react-router-with-query/package.json
+++ b/packages/react-router-with-query/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/react-router-with-query",
-  "version": "1.51.7",
+  "version": "1.51.9",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/react-router/package.json b/packages/react-router/package.json
index d2697d2a2..11788f2ef 100644
--- a/packages/react-router/package.json
+++ b/packages/react-router/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/react-router",
-  "version": "1.51.7",
+  "version": "1.51.9",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/react-router/src/qss.ts b/packages/react-router/src/qss.ts
index b5ec8e9e4..b08d5878f 100644
--- a/packages/react-router/src/qss.ts
+++ b/packages/react-router/src/qss.ts
@@ -68,6 +68,7 @@ export function decode(str: any, pfx?: string) {
     const equalIndex = tmp.indexOf('=')
     if (equalIndex !== -1) {
       k = tmp.slice(0, equalIndex)
+      k = decodeURIComponent(k)
       const value = tmp.slice(equalIndex + 1)
       if (out[k] !== void 0) {
         // @ts-expect-error
@@ -77,6 +78,7 @@ export function decode(str: any, pfx?: string) {
       }
     } else {
       k = tmp
+      k = decodeURIComponent(k)
       out[k] = ''
     }
   }
diff --git a/packages/react-router/src/route.ts b/packages/react-router/src/route.ts
index 000bdef20..7797b496b 100644
--- a/packages/react-router/src/route.ts
+++ b/packages/react-router/src/route.ts
@@ -879,13 +879,45 @@ export class Route<
     TBeforeLoadFn
   >
 
-  // Set up in this.init()
+  // The following properties are set up in this.init()
   parentRoute!: TParentRoute
-  id!: TId
-  // customId!: TCustomId
-  path!: TPath
-  fullPath!: TFullPath
-  to!: TrimPathRight<TFullPath>
+  private _id!: TId
+  private _path!: TPath
+  private _fullPath!: TFullPath
+  private _to!: TrimPathRight<TFullPath>
+
+  public get to() {
+    invariant(
+      this._to,
+      `trying to access property 'to' on a route which is not initialized yet. Route properties are only available after 'createRouter' completed.`,
+    )
+    return this._to
+  }
+
+  public get id() {
+    invariant(
+      this._id,
+      `trying to access property 'id' on a route which is not initialized yet. Route properties are only available after 'createRouter' completed.`,
+    )
+    return this._id
+  }
+
+  public get path() {
+    invariant(
+      // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+      this.isRoot || this._id || this._path,
+      `trying to access property 'path' on a route which is not initialized yet. Route properties are only available after 'createRouter' completed.`,
+    )
+    return this._path
+  }
+
+  public get fullPath() {
+    invariant(
+      this._fullPath,
+      `trying to access property 'fullPath' on a route which is not initialized yet. Route properties are only available after 'createRouter' completed.`,
+    )
+    return this._fullPath
+  }
 
   // Optional
   children?: TChildren
@@ -981,7 +1013,7 @@ export class Route<
     this.parentRoute = this.options.getParentRoute?.()
 
     if (isRoot) {
-      this.path = rootRouteId as TPath
+      this._path = rootRouteId as TPath
     } else {
       invariant(
         this.parentRoute,
@@ -1017,11 +1049,11 @@ export class Route<
     const fullPath =
       id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path])
 
-    this.path = path as TPath
-    this.id = id as TId
+    this._path = path as TPath
+    this._id = id as TId
     // this.customId = customId as TCustomId
-    this.fullPath = fullPath as TFullPath
-    this.to = fullPath as TrimPathRight<TFullPath>
+    this._fullPath = fullPath as TFullPath
+    this._to = fullPath as TrimPathRight<TFullPath>
   }
 
   addChildren<
diff --git a/packages/router-arktype-adapter/package.json b/packages/router-arktype-adapter/package.json
index ba88b762c..9986fb109 100644
--- a/packages/router-arktype-adapter/package.json
+++ b/packages/router-arktype-adapter/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/router-arktype-adapter",
-  "version": "1.51.7",
+  "version": "1.51.9",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/router-devtools/package.json b/packages/router-devtools/package.json
index 78f4c78e8..87da2a537 100644
--- a/packages/router-devtools/package.json
+++ b/packages/router-devtools/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/router-devtools",
-  "version": "1.51.7",
+  "version": "1.51.9",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/router-generator/src/config.ts b/packages/router-generator/src/config.ts
index 9c96132b4..0f36cf3cb 100644
--- a/packages/router-generator/src/config.ts
+++ b/packages/router-generator/src/config.ts
@@ -29,6 +29,8 @@ export const configSchema = z.object({
     .optional()
     .default(['/* prettier-ignore-end */']),
   autoCodeSplitting: z.boolean().optional(),
+  indexToken: z.string().optional().default('index'),
+  routeToken: z.string().optional().default('route'),
   experimental: z
     .object({
       // TODO: Remove this option in the next major release (v2).
@@ -94,5 +96,26 @@ export function getConfig(
     }
   }
 
+  validateConfig(config)
+  return config
+}
+
+function validateConfig(config: Config) {
+  if (typeof config.experimental?.enableCodeSplitting !== 'undefined') {
+    const message = `
+------
+⚠️ ⚠️ ⚠️
+ERROR: The "experimental.enableCodeSplitting" flag has been made stable and is now "autoCodeSplitting". Please update your configuration file to use "autoCodeSplitting" instead of "experimental.enableCodeSplitting".
+------
+`
+    console.error(message)
+    throw new Error(message)
+  }
+
+  if (config.indexToken === config.routeToken) {
+    throw new Error(
+      `The "indexToken" and "routeToken" options must be different.`,
+    )
+  }
   return config
 }
diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts
index 90622fd0a..02ed11893 100644
--- a/packages/router-generator/src/generator.ts
+++ b/packages/router-generator/src/generator.ts
@@ -100,7 +100,7 @@ async function getRouteNodes(config: Config) {
             routePath = routePath.replace(/\/lazy$/, '')
           }
 
-          const isRoute = routePath.endsWith('/route')
+          const isRoute = routePath.endsWith(`/${config.routeToken}`)
           const isComponent = routePath.endsWith('/component')
           const isErrorComponent = routePath.endsWith('/errorComponent')
           const isPendingComponent = routePath.endsWith('/pendingComponent')
@@ -110,8 +110,12 @@ async function getRouteNodes(config: Config) {
           )
 
           const segments = routePath.split('/')
+          const lastRouteSegment = segments[segments.length - 1]
           const isLayout =
-            segments[segments.length - 1]?.startsWith('_') || false
+            (lastRouteSegment !== config.indexToken &&
+              lastRouteSegment !== config.routeToken &&
+              lastRouteSegment?.startsWith('_')) ||
+            false
 
           ;(
             [
@@ -129,15 +133,18 @@ async function getRouteNodes(config: Config) {
           })
 
           routePath = routePath.replace(
-            /\/(component|errorComponent|pendingComponent|loader|route|lazy)$/,
+            new RegExp(
+              `/(component|errorComponent|pendingComponent|loader|${config.routeToken}|lazy)$`,
+            ),
             '',
           )
 
-          if (routePath === 'index') {
+          if (routePath === config.indexToken) {
             routePath = '/'
           }
 
-          routePath = routePath.replace(/\/index$/, '/') || '/'
+          routePath =
+            routePath.replace(new RegExp(`/${config.indexToken}$`), '/') || '/'
 
           routeNodes.push({
             filePath,
@@ -218,14 +225,16 @@ export async function generator(config: Config) {
   const preRouteNodes = multiSortBy(beforeRouteNodes, [
     (d) => (d.routePath === '/' ? -1 : 1),
     (d) => d.routePath?.split('/').length,
-    (d) => (d.filePath.match(/[./]index[.]/) ? 1 : -1),
+    (d) =>
+      d.filePath.match(new RegExp(`[./]${config.indexToken}[.]`)) ? 1 : -1,
     (d) =>
       d.filePath.match(
         /[./](component|errorComponent|pendingComponent|loader|lazy)[.]/,
       )
         ? 1
         : -1,
-    (d) => (d.filePath.match(/[./]route[.]/) ? -1 : 1),
+    (d) =>
+      d.filePath.match(new RegExp(`[./]${config.routeToken}[.]`)) ? -1 : 1,
     (d) => (d.routePath?.endsWith('/') ? -1 : 1),
     (d) => d.routePath,
   ]).filter((d) => ![`/${rootPathId}`].includes(d.routePath || ''))
@@ -542,7 +551,7 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
   const sortedRouteNodes = multiSortBy(routeNodes, [
     (d) => (d.routePath?.includes(`/${rootPathId}`) ? -1 : 1),
     (d) => d.routePath?.split('/').length,
-    (d) => (d.routePath?.endsWith("index'") ? -1 : 1),
+    (d) => (d.routePath?.endsWith(config.indexToken) ? -1 : 1),
     (d) => d,
   ])
 
@@ -1044,13 +1053,14 @@ export type StartAPIRoutePathSegment = {
  */
 export function startAPIRouteSegmentsFromTSRFilePath(
   src: string,
+  config: Config,
 ): Array<StartAPIRoutePathSegment> {
   const routePath = determineInitialRoutePath(src)
 
   const parts = routePath
     .replaceAll('.', '/')
     .split('/')
-    .filter((p) => !!p && p !== 'index')
+    .filter((p) => !!p && p !== config.indexToken)
   const segments: Array<StartAPIRoutePathSegment> = parts.map((part) => {
     if (part.startsWith('$')) {
       if (part === '$') {
diff --git a/packages/router-plugin/src/core/router-code-splitter-plugin.ts b/packages/router-plugin/src/core/router-code-splitter-plugin.ts
index 54264722c..6498eab42 100644
--- a/packages/router-plugin/src/core/router-code-splitter-plugin.ts
+++ b/packages/router-plugin/src/core/router-code-splitter-plugin.ts
@@ -172,7 +172,7 @@ export const unpluginRouterCodeSplitterFactory: UnpluginFactory<
       configResolved(config) {
         ROOT = config.root
 
-        userConfig = CHECK_USER_FLAGS_TO_BE_CHANGED(getConfig(options, ROOT))
+        userConfig = getConfig(options, ROOT)
       },
     },
 
@@ -193,7 +193,7 @@ export const unpluginRouterCodeSplitterFactory: UnpluginFactory<
         )
       })
 
-      userConfig = CHECK_USER_FLAGS_TO_BE_CHANGED(getConfig(options, ROOT))
+      userConfig = getConfig(options, ROOT)
     },
 
     webpack(compiler) {
@@ -213,7 +213,7 @@ export const unpluginRouterCodeSplitterFactory: UnpluginFactory<
         )
       })
 
-      userConfig = CHECK_USER_FLAGS_TO_BE_CHANGED(getConfig(options, ROOT))
+      userConfig = getConfig(options, ROOT)
 
       if (
         userConfig.autoCodeSplitting &&
@@ -229,18 +229,3 @@ export const unpluginRouterCodeSplitterFactory: UnpluginFactory<
     },
   }
 }
-
-function CHECK_USER_FLAGS_TO_BE_CHANGED(config: Config): Config {
-  if (typeof config.experimental?.enableCodeSplitting !== 'undefined') {
-    const message = `
-------
-⚠️ ⚠️ ⚠️
-ERROR: The "experimental.enableCodeSplitting" flag has been made stable and is now "autoCodeSplitting". Please update your configuration file to use "autoCodeSplitting" instead of "experimental.enableCodeSplitting".
-------
-`
-    console.error(message)
-    throw new Error(message)
-  }
-
-  return config
-}
diff --git a/packages/router-valibot-adapter/package.json b/packages/router-valibot-adapter/package.json
index 73dc2b19b..c777d661a 100644
--- a/packages/router-valibot-adapter/package.json
+++ b/packages/router-valibot-adapter/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/router-valibot-adapter",
-  "version": "1.51.7",
+  "version": "1.51.9",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/router-zod-adapter/package.json b/packages/router-zod-adapter/package.json
index ca4f8c820..74b61f940 100644
--- a/packages/router-zod-adapter/package.json
+++ b/packages/router-zod-adapter/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/router-zod-adapter",
-  "version": "1.51.7",
+  "version": "1.51.9",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/start/package.json b/packages/start/package.json
index 3bb14ca92..c4930cfdd 100644
--- a/packages/start/package.json
+++ b/packages/start/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/start",
-  "version": "1.51.7",
+  "version": "1.51.9",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/start/src/config/index.ts b/packages/start/src/config/index.ts
index 10efa04d2..8c42a3f70 100644
--- a/packages/start/src/config/index.ts
+++ b/packages/start/src/config/index.ts
@@ -4,9 +4,10 @@ import { readFile } from 'node:fs/promises'
 import { fileURLToPath } from 'node:url'
 import reactRefresh from '@vitejs/plugin-react'
 import { resolve } from 'import-meta-resolve'
-import { TanStackRouterVite, configSchema } from '@tanstack/router-plugin/vite'
+import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
 import { TanStackStartVite } from '@tanstack/start-vite-plugin'
 import {
+  configSchema,
   getConfig,
   startAPIRouteSegmentsFromTSRFilePath,
 } from '@tanstack/router-generator'
@@ -626,7 +627,10 @@ function tsrFileRouter(opts: {
       toPath(src: string): string {
         const inputPath = vinxiFsRouterCleanPath(src, this.config)
 
-        const segments = startAPIRouteSegmentsFromTSRFilePath(inputPath)
+        const segments = startAPIRouteSegmentsFromTSRFilePath(
+          inputPath,
+          opts.tsrConfig,
+        )
 
         const pathname = segments
           .map((part) => {


Test patch:
diff --git a/packages/react-router/tests/createRoute.test.ts b/packages/react-router/tests/createRoute.test.ts
deleted file mode 100644
index efa13c814..000000000
--- a/packages/react-router/tests/createRoute.test.ts
+++ /dev/null
@@ -1,330 +0,0 @@
-import { describe, it } from 'vitest'
-import { z } from 'zod'
-import { createMemoryHistory, RootRoute, Route, createRouter } from '../src'
-
-const lazyTest = (comp: any, key: any) => {
-  comp.preload = () => {}
-  return comp
-}
-
-// Write a test
-describe('everything', () => {
-  it('should work', () => {
-    // // Build our routes. We could do this in our component, too.
-    // const rootRoute = createRootRoute()
-    // const indexRoute = createRoute({
-    //   getParentRoute: () => rootRoute,
-    //   path: '/',
-    //   validateSearch: (search) =>
-    //     z
-    //       .object({
-    //         version: z.number(),
-    //       })
-    //       .parse(search),
-    // })
-    // const testRoute = createRoute({
-    //   getParentRoute: () => rootRoute,
-    //   component: lazyTest(() => import('./TestComponent'), 'NamedComponent'),
-    //   path: 'test',
-    //   validateSearch: (search) =>
-    //     z
-    //       .object({
-    //         version: z.number(),
-    //         isGood: z.boolean(),
-    //       })
-    //       .parse(search),
-    // })
-    // const dashboardRoute = createRoute({
-    //   getParentRoute: () => rootRoute,
-    //   path: 'dashboard',
-    //   loader: async () => {
-    //     console.info('Fetching all invoices...')
-    //     return {
-    //       invoices: 'await fetchInvoices()',
-    //     }
-    //   },
-    // })
-    // const dashboardIndexRoute = createRoute({
-    //   getParentRoute: () => dashboardRoute,
-    //   path: '/',
-    // })
-    // const invoicesRoute = createRoute({
-    //   getParentRoute: () => dashboardRoute,
-    //   path: 'invoices',
-    // })
-    // const invoicesIndexRoute = createRoute({
-    //   getParentRoute: () => invoicesRoute,
-    //   path: '/',
-    // })
-    // const invoiceRoute = createRoute({
-    //   getParentRoute: () => invoicesRoute,
-    //   path: '$invoiceId',
-    //   parseParams: ({ invoiceId }) => ({ invoiceId: Number(invoiceId) }),
-    //   stringifyParams: ({ invoiceId }) => ({
-    //     invoiceId: String(invoiceId),
-    //   }),
-    //   loader: async ({ params: { invoiceId } }) => {
-    //     console.info('Fetching invoice...')
-    //     return {
-    //       invoice: 'await fetchInvoiceById(invoiceId!)',
-    //     }
-    //   },
-    // })
-    // const usersRoute = createRoute({
-    //   getParentRoute: () => dashboardRoute,
-    //   path: 'users',
-    //   loader: async () => {
-    //     return {
-    //       users: 'await fetchUsers()',
-    //     }
-    //   },
-    //   validateSearch: (search) =>
-    //     z
-    //       .object({
-    //         usersView: z
-    //           .object({
-    //             sortBy: z.enum(['name', 'id', 'email']).optional(),
-    //             filterBy: z.string().optional(),
-    //           })
-    //           .optional(),
-    //       })
-    //       .parse(search),
-    //   preSearchFilters: [
-    //     // Keep the usersView search param around
-    //     // while in this route (or it's children!)
-    //     (search) => ({
-    //       ...search,
-    //       usersView: {
-    //         ...search.usersView,
-    //       },
-    //     }),
-    //   ],
-    // })
-    // const userRoute = createRoute({
-    //   getParentRoute: () => usersRoute,
-    //   path: '$userId',
-    //   loader: async ({ params: { userId }, search }) => {
-    //     return {
-    //       user: 'await fetchUserById(userId!)',
-    //     }
-    //   },
-    // })
-    // const authenticatedRoute = createRoute({
-    //   getParentRoute: () => rootRoute,
-    //   path: 'authenticated/', // Trailing slash doesn't mean anything
-    // })
-    // const authenticatedIndexRoute = createRoute({
-    //   getParentRoute: () => authenticatedRoute,
-    //   path: '/',
-    // })
-    // const layoutRoute = createRoute({
-    //   getParentRoute: () => rootRoute,
-    //   id: 'layout',
-    //   component: () => 'layout-wrapper',
-    //   validateSearch: (search) =>
-    //     z
-    //       .object({
-    //         isLayout: z.boolean(),
-    //       })
-    //       .parse(search),
-    // })
-    // const layoutARoute = createRoute({
-    //   getParentRoute: () => layoutRoute,
-    //   path: 'layout-a',
-    //   component: () => 'layout-a',
-    // })
-    // const layoutBRoute = createRoute({
-    //   getParentRoute: () => layoutRoute,
-    //   path: 'layout-b',
-    //   component: () => 'layout-b',
-    // })
-    // const routeTree = rootRoute.addChildren([
-    //   indexRoute,
-    //   testRoute,
-    //   dashboardRoute.addChildren([
-    //     dashboardIndexRoute,
-    //     invoicesRoute.addChildren([invoicesIndexRoute, invoiceRoute]),
-    //     usersRoute.addChildren([userRoute]),
-    //   ]),
-    //   authenticatedRoute.addChildren([authenticatedIndexRoute]),
-    //   layoutRoute.addChildren([layoutARoute, layoutBRoute]),
-    // ])
-    // const router = createRouter({
-    //   routeTree,
-    //   history: createMemoryHistory({
-    //     initialEntries: ['/?version=1'],
-    //   }),
-    // })
-    // const route = router.getRoute('/dashboard/users/$userId')
-    // router.buildLink({
-    //   to: '/dashboard/users/$userId',
-    //   params: {
-    //     userId: '2',
-    //   },
-    //   search: (prev) => ({
-    //     usersView: {
-    //       sortBy: 'email',
-    //     },
-    //   }),
-    // })
-    // // @ts-expect-error
-    // router.buildLink({
-    //   from: '/',
-    //   to: '/test',
-    // })
-    // router.buildLink({
-    //   from: '/',
-    //   to: '/test',
-    //   search: () => {
-    //     return {
-    //       version: 2,
-    //       isGood: true,
-    //     }
-    //   },
-    // })
-    // router.buildLink({
-    //   from: '/test',
-    //   to: '/',
-    // })
-    // router.buildLink({
-    //   from: route.id,
-    //   to: '',
-    // })
-    // router.buildLink({
-    //   from: '/dashboard',
-    //   to: '/dashboard/invoices',
-    //   params: {
-    //     invoiceId: 2,
-    //   },
-    // })
-    // router.buildLink({
-    //   from: '/dashboard',
-    //   to: '/dashboard/invoices/$invoiceId',
-    //   params: {
-    //     // @ts-expect-error
-    //     invoiceId: '2',
-    //   },
-    // })
-    // router.buildLink({
-    //   to: '/dashboard/invoices/$invoiceId',
-    //   params: {
-    //     invoiceId: 2,
-    //   },
-    // })
-    // router.buildLink({
-    //   to: '/',
-    //   search: {
-    //     version: 2,
-    //   },
-    // })
-    // router.buildLink({
-    //   to: '/dashboard/users/$userId',
-    //   // @ts-expect-error
-    //   params: (current) => ({
-    //     userId: current?.invoiceId,
-    //   }),
-    //   search: (old) => ({
-    //     usersView: {
-    //       sortBy: 'email' as const,
-    //       filterBy: String(old.version),
-    //     },
-    //   }),
-    // })
-    // router.buildLink({
-    //   from: '/dashboard/invoices/$invoiceId',
-    //   to: '/dashboard/users/$userId',
-    //   params: (current) => ({
-    //     userId: `${current?.invoiceId}`,
-    //   }),
-    //   search: (prev) => {
-    //     return {
-    //       usersView: {
-    //         sortBy: 'name' as const,
-    //         filterBy: 'tanner',
-    //       },
-    //     }
-    //   },
-    // })
-    // router.buildLink({
-    //   from: '/dashboard/users/$userId',
-    //   to: '/',
-    //   search: (prev) => {
-    //     return {
-    //       version: 2,
-    //     }
-    //   },
-    // })
-    // router.buildLink({
-    //   from: '/',
-    //   to: '/dashboard/users/$userId',
-    //   params: {
-    //     userId: '2',
-    //   },
-    //   search: (prev) => ({
-    //     usersView: {
-    //       sortBy: 'id',
-    //       filterBy: `${prev.version}`,
-    //     },
-    //   }),
-    // })
-    // router.navigate({
-    //   search: (prev: any) => ({
-    //     version: prev.version,
-    //   }),
-    // })
-    // router.buildLink({
-    //   from: '/dashboard/invoices',
-    //   to: '/dashboard',
-    // })
-    // router.buildLink({
-    //   from: '/',
-    //   // @ts-expect-error
-    //   to: '/does-not-exist',
-    // })
-    // router.buildLink({
-    //   to: '/dashboard/invoices/$invoiceId',
-    //   params: {
-    //     invoiceId: 2,
-    //   },
-    // })
-    // router.buildLink({
-    //   from: '/dashboard/invoices/$invoiceId',
-    //   to: '.',
-    //   params: (d) => ({
-    //     invoiceId: d.invoiceId,
-    //   }),
-    // })
-    // router.buildLink({
-    //   from: '/dashboard/invoices/$invoiceId',
-    //   to: testRoute.fullPath,
-    //   search: {
-    //     version: 2,
-    //     isGood: true,
-    //   },
-    // })
-    // router.buildLink({
-    //   to: '/layout-a',
-    //   search: (current) => ({
-    //     isLayout: !!current.version,
-    //   }),
-    // })
-    // router.buildLink({
-    //   to: '/',
-    //   state: true,
-    // })
-    // router.buildLink({
-    //   to: '/',
-    //   state: {},
-    // })
-    // router.buildLink({
-    //   to: '/',
-    //   state: (prev) => prev,
-    // })
-    // router.buildLink({
-    //   to: '/',
-    //   state: (prev) => ({
-    //     test: true,
-    //   }),
-    // })
-  })
-})
diff --git a/packages/react-router/tests/navigate.test.tsx b/packages/react-router/tests/navigate.test.tsx
index 61e34f55c..cf91b6612 100644
--- a/packages/react-router/tests/navigate.test.tsx
+++ b/packages/react-router/tests/navigate.test.tsx
@@ -68,6 +68,15 @@ function createTestRouter(initialHistory?: RouterHistory) {
     getParentRoute: () => gLayoutRoute,
     path: '$username',
   })
+  const searchRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: 'search',
+    validateSearch: (search: Record<string, unknown>) => {
+      return {
+        ['foo=bar']: Number(search['foo=bar'] ?? 1),
+      }
+    },
+  })
 
   const projectTree = projectRoute.addChildren([
     projectIdRoute.addChildren([
@@ -460,4 +469,22 @@ describe('router.navigate navigation using layout routes resolves correctly', as
 
     expect(router.state.location.pathname).toBe('/g/tkdodo')
   })
+
+  it('should handle search params with special characters', async () => {
+    const { router } = createTestRouter(
+      createMemoryHistory({ initialEntries: ['/search?foo%3Dbar=2'] }),
+    )
+
+    await router.load()
+
+    expect(router.state.location.pathname).toBe('/search')
+    expect(router.state.location.search).toStrictEqual({ 'foo=bar': 2 })
+
+    await router.navigate({
+      search: { 'foo=bar': 3 },
+    })
+    await router.invalidate()
+
+    expect(router.state.location.search).toStrictEqual({ 'foo=bar': 3 })
+  })
 })
diff --git a/packages/react-router/tests/qss.test.ts b/packages/react-router/tests/qss.test.ts
index b7aebec20..7f1bbca23 100644
--- a/packages/react-router/tests/qss.test.ts
+++ b/packages/react-router/tests/qss.test.ts
@@ -32,6 +32,12 @@ describe('encode function', () => {
     const queryString = encode(obj)
     expect(queryString).toEqual('token=foo%3F&key=value%3D')
   })
+
+  it('should handle encoding a top-level key with a special character', () => {
+    const obj = { 'foo=bar': 1 }
+    const queryString = encode(obj)
+    expect(queryString).toEqual('foo%3Dbar=1')
+  })
 })
 
 describe('decode function', () => {
@@ -64,4 +70,22 @@ describe('decode function', () => {
     const decodedObj = decode(queryString)
     expect(decodedObj).toEqual({ token: 'foo?', key: 'value=' })
   })
+
+  it('should handle decoding a top-level key with a special character', () => {
+    const queryString = 'foo%3Dbar=1'
+    const decodedObj = decode(queryString)
+    expect(decodedObj).toEqual({ 'foo=bar': 1 })
+  })
+
+  it('should handle decoding a top-level key with a special character and without a value', () => {
+    const queryString = 'foo%3Dbar='
+    const decodedObj = decode(queryString)
+    expect(decodedObj).toEqual({ 'foo=bar': '' })
+  })
+
+  it('should handle decoding a value-less top-level key with a special character', () => {
+    const queryString = 'foo%3Dbar'
+    const decodedObj = decode(queryString)
+    expect(decodedObj).toEqual({ 'foo=bar': '' })
+  })
 })
diff --git a/packages/react-router/tests/route.test.ts b/packages/react-router/tests/route.test.ts
deleted file mode 100644
index a001f7bfa..000000000
--- a/packages/react-router/tests/route.test.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/* eslint-disable */
-import { describe, it, expect } from 'vitest'
-import { getRouteApi, createRoute } from '../src'
-
-describe('getRouteApi', () => {
-  it('should have the useMatch hook', () => {
-    const api = getRouteApi('foo')
-    expect(api.useMatch).toBeDefined()
-  })
-
-  it('should have the useRouteContext hook', () => {
-    const api = getRouteApi('foo')
-    expect(api.useRouteContext).toBeDefined()
-  })
-
-  it('should have the useSearch hook', () => {
-    const api = getRouteApi('foo')
-    expect(api.useSearch).toBeDefined()
-  })
-
-  it('should have the useParams hook', () => {
-    const api = getRouteApi('foo')
-    expect(api.useParams).toBeDefined()
-  })
-
-  it('should have the useLoaderData hook', () => {
-    const api = getRouteApi('foo')
-    expect(api.useLoaderData).toBeDefined()
-  })
-
-  it('should have the useLoaderDeps hook', () => {
-    const api = getRouteApi('foo')
-    expect(api.useLoaderDeps).toBeDefined()
-  })
-
-  it('should have the useNavigate hook', () => {
-    const api = getRouteApi('foo')
-    expect(api.useNavigate).toBeDefined()
-  })
-})
-
-describe('createRoute has the same hooks as getRouteApi', () => {
-  const routeApi = getRouteApi('foo')
-  const hookNames = Object.keys(routeApi).filter((key) => key.startsWith('use'))
-  const route = createRoute({} as any)
-
-  it.each(hookNames.map((name) => [name]))(
-    'should have the "%s" hook defined',
-    (hookName) => {
-      expect(route[hookName as keyof typeof route]).toBeDefined()
-    },
-  )
-})
diff --git a/packages/react-router/tests/route.test.tsx b/packages/react-router/tests/route.test.tsx
new file mode 100644
index 000000000..fd881e328
--- /dev/null
+++ b/packages/react-router/tests/route.test.tsx
@@ -0,0 +1,140 @@
+/* eslint-disable */
+import { describe, it, expect } from 'vitest'
+import {
+  getRouteApi,
+  createRoute,
+  createRootRoute,
+  createRouter,
+  useNavigate,
+} from '../src'
+import React from 'react'
+import exp from 'constants'
+
+describe('getRouteApi', () => {
+  it('should have the useMatch hook', () => {
+    const api = getRouteApi('foo')
+    expect(api.useMatch).toBeDefined()
+  })
+
+  it('should have the useRouteContext hook', () => {
+    const api = getRouteApi('foo')
+    expect(api.useRouteContext).toBeDefined()
+  })
+
+  it('should have the useSearch hook', () => {
+    const api = getRouteApi('foo')
+    expect(api.useSearch).toBeDefined()
+  })
+
+  it('should have the useParams hook', () => {
+    const api = getRouteApi('foo')
+    expect(api.useParams).toBeDefined()
+  })
+
+  it('should have the useLoaderData hook', () => {
+    const api = getRouteApi('foo')
+    expect(api.useLoaderData).toBeDefined()
+  })
+
+  it('should have the useLoaderDeps hook', () => {
+    const api = getRouteApi('foo')
+    expect(api.useLoaderDeps).toBeDefined()
+  })
+
+  it('should have the useNavigate hook', () => {
+    const api = getRouteApi('foo')
+    expect(api.useNavigate).toBeDefined()
+  })
+})
+
+describe('createRoute has the same hooks as getRouteApi', () => {
+  const routeApi = getRouteApi('foo')
+  const hookNames = Object.keys(routeApi).filter((key) => key.startsWith('use'))
+  const route = createRoute({} as any)
+
+  it.each(hookNames.map((name) => [name]))(
+    'should have the "%s" hook defined',
+    (hookName) => {
+      expect(route[hookName as keyof typeof route]).toBeDefined()
+    },
+  )
+})
+
+describe('throws invariant exception when trying to access properties before `createRouter` completed', () => {
+  function setup() {
+    const rootRoute = createRootRoute()
+
+    const IndexComponent = () => {
+      const navigate = useNavigate()
+      return (
+        <React.Fragment>
+          <h1>Index</h1>
+          <button onClick={() => navigate({ to: '/' })}>Index</button>
+          <button onClick={() => navigate({ to: '/posts' })}>Posts</button>
+        </React.Fragment>
+      )
+    }
+
+    const indexRoute = createRoute({
+      getParentRoute: () => rootRoute,
+      path: '/',
+      component: IndexComponent,
+    })
+
+    const postsRoute = createRoute({
+      getParentRoute: () => rootRoute,
+      path: '/posts',
+      component: () => {
+        return (
+          <React.Fragment>
+            <h1>Posts</h1>
+          </React.Fragment>
+        )
+      },
+    })
+    const initRouter = () =>
+      createRouter({
+        routeTree: rootRoute.addChildren([indexRoute, postsRoute]),
+      })
+    return { initRouter, rootRoute, indexRoute, postsRoute }
+  }
+
+  it('to', () => {
+    const { initRouter, indexRoute, postsRoute } = setup()
+
+    const expectedError = `Invariant failed: trying to access property 'to' on a route which is not initialized yet. Route properties are only available after 'createRouter' completed.`
+    expect(() => indexRoute.to).toThrowError(expectedError)
+    expect(() => postsRoute.to).toThrowError(expectedError)
+
+    initRouter()
+
+    expect(indexRoute.to).toBe('/')
+    expect(postsRoute.to).toBe('/posts')
+  })
+
+  it('fullPath', () => {
+    const { initRouter, indexRoute, postsRoute } = setup()
+
+    const expectedError = `trying to access property 'fullPath' on a route which is not initialized yet. Route properties are only available after 'createRouter' completed.`
+    expect(() => indexRoute.fullPath).toThrowError(expectedError)
+    expect(() => postsRoute.fullPath).toThrowError(expectedError)
+
+    initRouter()
+
+    expect(indexRoute.fullPath).toBe('/')
+    expect(postsRoute.fullPath).toBe('/posts')
+  })
+
+  it('id', () => {
+    const { initRouter, indexRoute, postsRoute } = setup()
+
+    const expectedError = `Invariant failed: trying to access property 'id' on a route which is not initialized yet. Route properties are only available after 'createRouter' completed.`
+    expect(() => indexRoute.id).toThrowError(expectedError)
+    expect(() => postsRoute.id).toThrowError(expectedError)
+
+    initRouter()
+
+    expect(indexRoute.to).toBe('/')
+    expect(postsRoute.to).toBe('/posts')
+  })
+})
diff --git a/packages/router-generator/tests/generator.test.ts b/packages/router-generator/tests/generator.test.ts
index 218c1bda3..a0cc94274 100644
--- a/packages/router-generator/tests/generator.test.ts
+++ b/packages/router-generator/tests/generator.test.ts
@@ -47,6 +47,10 @@ function rewriteConfigByFolderName(folderName: string, config: Config) {
     case 'no-manifest':
       config.disableManifestGeneration = true
       break
+    case 'custom-tokens':
+      config.indexToken = '_1nd3x'
+      config.routeToken = '_r0ut3_'
+      break
     default:
       break
   }
diff --git a/packages/router-generator/tests/generator/custom-tokens/routeTree.snapshot.ts b/packages/router-generator/tests/generator/custom-tokens/routeTree.snapshot.ts
new file mode 100644
index 000000000..3fa9ec1f8
--- /dev/null
+++ b/packages/router-generator/tests/generator/custom-tokens/routeTree.snapshot.ts
@@ -0,0 +1,193 @@
+/* prettier-ignore-start */
+
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file is auto-generated by TanStack Router
+
+// Import Routes
+
+import { Route as rootRoute } from './routes/__root'
+import { Route as PostsR0ut3Import } from './routes/posts/_r0ut3_'
+import { Route as BlogR0ut3Import } from './routes/blog/_r0ut3_'
+import { Route as R1nd3xImport } from './routes/_1nd3x'
+import { Route as Posts1nd3xImport } from './routes/posts/_1nd3x'
+import { Route as Blog1nd3xImport } from './routes/blog/_1nd3x'
+import { Route as BlogSlugImport } from './routes/blog/$slug'
+import { Route as PostsPostId1nd3xImport } from './routes/posts/$postId/_1nd3x'
+import { Route as PostsPostIdDeepImport } from './routes/posts/$postId/deep'
+
+// Create/Update Routes
+
+const PostsR0ut3Route = PostsR0ut3Import.update({
+  path: '/posts',
+  getParentRoute: () => rootRoute,
+} as any)
+
+const BlogR0ut3Route = BlogR0ut3Import.update({
+  path: '/blog',
+  getParentRoute: () => rootRoute,
+} as any)
+
+const R1nd3xRoute = R1nd3xImport.update({
+  path: '/',
+  getParentRoute: () => rootRoute,
+} as any)
+
+const Posts1nd3xRoute = Posts1nd3xImport.update({
+  path: '/',
+  getParentRoute: () => PostsR0ut3Route,
+} as any)
+
+const Blog1nd3xRoute = Blog1nd3xImport.update({
+  path: '/',
+  getParentRoute: () => BlogR0ut3Route,
+} as any)
+
+const BlogSlugRoute = BlogSlugImport.update({
+  path: '/$slug',
+  getParentRoute: () => BlogR0ut3Route,
+} as any)
+
+const PostsPostId1nd3xRoute = PostsPostId1nd3xImport.update({
+  path: '/$postId/',
+  getParentRoute: () => PostsR0ut3Route,
+} as any)
+
+const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({
+  path: '/$postId/deep',
+  getParentRoute: () => PostsR0ut3Route,
+} as any)
+
+// Populate the FileRoutesByPath interface
+
+declare module '@tanstack/react-router' {
+  interface FileRoutesByPath {
+    '/': {
+      id: '/'
+      path: '/'
+      fullPath: '/'
+      preLoaderRoute: typeof R1nd3xImport
+      parentRoute: typeof rootRoute
+    }
+    '/blog': {
+      id: '/blog'
+      path: '/blog'
+      fullPath: '/blog'
+      preLoaderRoute: typeof BlogR0ut3Import
+      parentRoute: typeof rootRoute
+    }
+    '/posts': {
+      id: '/posts'
+      path: '/posts'
+      fullPath: '/posts'
+      preLoaderRoute: typeof PostsR0ut3Import
+      parentRoute: typeof rootRoute
+    }
+    '/blog/$slug': {
+      id: '/blog/$slug'
+      path: '/$slug'
+      fullPath: '/blog/$slug'
+      preLoaderRoute: typeof BlogSlugImport
+      parentRoute: typeof BlogR0ut3Import
+    }
+    '/blog/': {
+      id: '/blog/'
+      path: '/'
+      fullPath: '/blog/'
+      preLoaderRoute: typeof Blog1nd3xImport
+      parentRoute: typeof BlogR0ut3Import
+    }
+    '/posts/': {
+      id: '/posts/'
+      path: '/'
+      fullPath: '/posts/'
+      preLoaderRoute: typeof Posts1nd3xImport
+      parentRoute: typeof PostsR0ut3Import
+    }
+    '/posts/$postId/deep': {
+      id: '/posts/$postId/deep'
+      path: '/$postId/deep'
+      fullPath: '/posts/$postId/deep'
+      preLoaderRoute: typeof PostsPostIdDeepImport
+      parentRoute: typeof PostsR0ut3Import
+    }
+    '/posts/$postId/': {
+      id: '/posts/$postId/'
+      path: '/$postId'
+      fullPath: '/posts/$postId'
+      preLoaderRoute: typeof PostsPostId1nd3xImport
+      parentRoute: typeof PostsR0ut3Import
+    }
+  }
+}
+
+// Create and export the route tree
+
+export const routeTree = rootRoute.addChildren({
+  R1nd3xRoute,
+  BlogR0ut3Route: BlogR0ut3Route.addChildren({ BlogSlugRoute, Blog1nd3xRoute }),
+  PostsR0ut3Route: PostsR0ut3Route.addChildren({
+    Posts1nd3xRoute,
+    PostsPostIdDeepRoute,
+    PostsPostId1nd3xRoute,
+  }),
+})
+
+/* prettier-ignore-end */
+
+/* ROUTE_MANIFEST_START
+{
+  "routes": {
+    "__root__": {
+      "filePath": "__root.tsx",
+      "children": [
+        "/",
+        "/blog",
+        "/posts"
+      ]
+    },
+    "/": {
+      "filePath": "_1nd3x.tsx"
+    },
+    "/blog": {
+      "filePath": "blog/_r0ut3_.tsx",
+      "children": [
+        "/blog/$slug",
+        "/blog/"
+      ]
+    },
+    "/posts": {
+      "filePath": "posts/_r0ut3_.tsx",
+      "children": [
+        "/posts/",
+        "/posts/$postId/deep",
+        "/posts/$postId/"
+      ]
+    },
+    "/blog/$slug": {
+      "filePath": "blog/$slug.tsx",
+      "parent": "/blog"
+    },
+    "/blog/": {
+      "filePath": "blog/_1nd3x.tsx",
+      "parent": "/blog"
+    },
+    "/posts/": {
+      "filePath": "posts/_1nd3x.tsx",
+      "parent": "/posts"
+    },
+    "/posts/$postId/deep": {
+      "filePath": "posts/$postId/deep.tsx",
+      "parent": "/posts"
+    },
+    "/posts/$postId/": {
+      "filePath": "posts/$postId/_1nd3x.tsx",
+      "parent": "/posts"
+    }
+  }
+}
+ROUTE_MANIFEST_END */
diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/_1nd3x.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/_1nd3x.tsx
new file mode 100644
index 000000000..ab504e42e
--- /dev/null
+++ b/packages/router-generator/tests/generator/custom-tokens/routes/_1nd3x.tsx
@@ -0,0 +1,1 @@
+/** */
diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/__root.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/__root.tsx
new file mode 100644
index 000000000..ab504e42e
--- /dev/null
+++ b/packages/router-generator/tests/generator/custom-tokens/routes/__root.tsx
@@ -0,0 +1,1 @@
+/** */
diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/blog/$slug.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/blog/$slug.tsx
new file mode 100644
index 000000000..ab504e42e
--- /dev/null
+++ b/packages/router-generator/tests/generator/custom-tokens/routes/blog/$slug.tsx
@@ -0,0 +1,1 @@
+/** */
diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/blog/_1nd3x.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/blog/_1nd3x.tsx
new file mode 100644
index 000000000..ab504e42e
--- /dev/null
+++ b/packages/router-generator/tests/generator/custom-tokens/routes/blog/_1nd3x.tsx
@@ -0,0 +1,1 @@
+/** */
diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/blog/_r0ut3_.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/blog/_r0ut3_.tsx
new file mode 100644
index 000000000..ab504e42e
--- /dev/null
+++ b/packages/router-generator/tests/generator/custom-tokens/routes/blog/_r0ut3_.tsx
@@ -0,0 +1,1 @@
+/** */
diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/_1nd3x.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/_1nd3x.tsx
new file mode 100644
index 000000000..79a9626b5
--- /dev/null
+++ b/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/_1nd3x.tsx
@@ -0,0 +1,1 @@
+/* */
diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/deep.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/deep.tsx
new file mode 100644
index 000000000..ab504e42e
--- /dev/null
+++ b/packages/router-generator/tests/generator/custom-tokens/routes/posts/$postId/deep.tsx
@@ -0,0 +1,1 @@
+/** */
diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/posts/_1nd3x.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/posts/_1nd3x.tsx
new file mode 100644
index 000000000..ab504e42e
--- /dev/null
+++ b/packages/router-generator/tests/generator/custom-tokens/routes/posts/_1nd3x.tsx
@@ -0,0 +1,1 @@
+/** */
diff --git a/packages/router-generator/tests/generator/custom-tokens/routes/posts/_r0ut3_.tsx b/packages/router-generator/tests/generator/custom-tokens/routes/posts/_r0ut3_.tsx
new file mode 100644
index 000000000..ab504e42e
--- /dev/null
+++ b/packages/router-generator/tests/generator/custom-tokens/routes/posts/_r0ut3_.tsx
@@ -0,0 +1,1 @@
+/** */