Repository: TanStack/router
Pull request #1562 (2024-05-05 13:59:44)

docs(examples): set correct correct server entry-point for production for "basic-ssr"
The server for the "Basic + SSR" (and the wip-with-bling) example is specifiying the wrong file name that gets built into the dist folder.


To reproduce:

1. Open the Stackblitz project: https://tanstack.com/router/latest/docs/framework/react/examples/basic-ssr-file-based
2. `npm i`
3. `npm run build`
4. `npm run serve`

Produces the following error:

```properties
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/projects/wmaivvaxx.github/dist/server/entry-server.tsx' imported from /home/projects/wmaivvaxx.github/server.js
    at __node_internal_captureLargerStackTrace2 (https://wmaivvaxxgithub-vsdf.w-staticblitz.com/builtins.575e820e.js:101:5528)
    at new NodeError (https://wmaivvaxxgithub-vsdf.w-staticblitz.com/builtins.575e820e.js:101:4214)
    at finalizeResolution (https://wmaivvaxxgithub-vsdf.w-staticblitz.com/builtins.575e820e.js:158:11255)
```


Patch:
diff --git a/docs/framework/react/guide/file-based-routing.md b/docs/framework/react/guide/file-based-routing.md
index 17edb70e7..1be45895f 100644
--- a/docs/framework/react/guide/file-based-routing.md
+++ b/docs/framework/react/guide/file-based-routing.md
@@ -94,7 +94,7 @@ The following options are available for configuration via the `tsr.config.json`
 - **`routeFileIgnorePrefix`**
   - (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 file and directories in the route directory. It can be used in regular expression format. For example `.((css|const).ts)|test-page` can ignore `.css.ts` and `.const.ts` file and ignore file and directories includes name with `test-page`
+  - (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`.
 - **`routesDirectory`**
   - (Required) The directory containing the routes relative to the cwd.
 - **`generatedRouteTree`**
diff --git a/examples/react/authenticated-routes/package.json b/examples/react/authenticated-routes/package.json
index 9087c0561..d2f06f6ba 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.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "@tanstack/router-vite-plugin": "^1.31.18",
     "axios": "^1.6.5",
     "immer": "^10.0.3",
diff --git a/examples/react/basic-default-search-params/package.json b/examples/react/basic-default-search-params/package.json
index a877c4c39..a77c9c5d3 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.17.8",
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "axios": "^1.6.5",
     "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 2c56a3b4d..8dc73609e 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.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "@tanstack/router-vite-plugin": "^1.31.18",
     "axios": "^1.6.5",
     "immer": "^10.0.3",
diff --git a/examples/react/basic-file-based/package.json b/examples/react/basic-file-based/package.json
index dcbbcca10..3ada633e4 100644
--- a/examples/react/basic-file-based/package.json
+++ b/examples/react/basic-file-based/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "@tanstack/router-vite-plugin": "^1.31.18",
     "axios": "^1.6.5",
     "immer": "^10.0.3",
diff --git a/examples/react/basic-react-query-file-based/package.json b/examples/react/basic-react-query-file-based/package.json
index b0d4311b3..42ff65923 100644
--- a/examples/react/basic-react-query-file-based/package.json
+++ b/examples/react/basic-react-query-file-based/package.json
@@ -11,8 +11,8 @@
   "dependencies": {
     "@tanstack/react-query": "^5.17.8",
     "@tanstack/react-query-devtools": "^5.17.8",
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "@tanstack/router-vite-plugin": "^1.31.18",
     "axios": "^1.6.5",
     "immer": "^10.0.3",
diff --git a/examples/react/basic-react-query/package.json b/examples/react/basic-react-query/package.json
index f44096283..7cbc444ed 100644
--- a/examples/react/basic-react-query/package.json
+++ b/examples/react/basic-react-query/package.json
@@ -11,8 +11,8 @@
   "dependencies": {
     "@tanstack/react-query": "^5.17.8",
     "@tanstack/react-query-devtools": "^5.17.8",
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "axios": "^1.6.5",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
diff --git a/examples/react/basic-ssr-file-based/package.json b/examples/react/basic-ssr-file-based/package.json
index 0e32d64d1..cf286a9c5 100644
--- a/examples/react/basic-ssr-file-based/package.json
+++ b/examples/react/basic-ssr-file-based/package.json
@@ -12,9 +12,9 @@
     "debug": "node --inspect-brk server"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/react-router-server": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/react-router-server": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "@tanstack/router-vite-plugin": "^1.31.18",
     "axios": "^1.6.5",
     "get-port": "^7.0.0",
diff --git a/examples/react/basic-ssr-file-based/server.js b/examples/react/basic-ssr-file-based/server.js
index 797de0c1f..ab88a1646 100644
--- a/examples/react/basic-ssr-file-based/server.js
+++ b/examples/react/basic-ssr-file-based/server.js
@@ -68,7 +68,7 @@ export async function createServer(
         if (!isProd) {
           return vite.ssrLoadModule('/src/entry-server.tsx')
         } else {
-          return import('./dist/server/entry-server.tsx')
+          return import('./dist/server/entry-server.js')
         }
       })()
 
diff --git a/examples/react/basic-ssr-streaming-file-based/package.json b/examples/react/basic-ssr-streaming-file-based/package.json
index 4964130e5..49591101e 100644
--- a/examples/react/basic-ssr-streaming-file-based/package.json
+++ b/examples/react/basic-ssr-streaming-file-based/package.json
@@ -12,9 +12,9 @@
     "debug": "node --inspect-brk server"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/react-router-server": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/react-router-server": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "@tanstack/router-vite-plugin": "^1.31.18",
     "axios": "^1.6.5",
     "get-port": "^7.0.0",
diff --git a/examples/react/basic-ssr-streaming-file-based/server.js b/examples/react/basic-ssr-streaming-file-based/server.js
index 797de0c1f..ab88a1646 100644
--- a/examples/react/basic-ssr-streaming-file-based/server.js
+++ b/examples/react/basic-ssr-streaming-file-based/server.js
@@ -68,7 +68,7 @@ export async function createServer(
         if (!isProd) {
           return vite.ssrLoadModule('/src/entry-server.tsx')
         } else {
-          return import('./dist/server/entry-server.tsx')
+          return import('./dist/server/entry-server.js')
         }
       })()
 
diff --git a/examples/react/basic/package.json b/examples/react/basic/package.json
index fb469a8ce..bf678d7f9 100644
--- a/examples/react/basic/package.json
+++ b/examples/react/basic/package.json
@@ -10,8 +10,8 @@
   },
   "dependencies": {
     "@tanstack/react-query": "^5.17.8",
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "axios": "^1.6.5",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
diff --git a/examples/react/deferred-data/package.json b/examples/react/deferred-data/package.json
index 123d6e55e..f2f626b3d 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.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "axios": "^1.6.5",
     "immer": "^10.0.3",
     "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 1adf812d4..1a88c2836 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.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "@tanstack/router-vite-plugin": "^1.31.18",
     "axios": "^1.6.5",
     "immer": "^10.0.3",
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 1f91da2e5..a257a5290 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.17.8",
     "@tanstack/react-query-devtools": "^5.17.8",
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "@tanstack/router-vite-plugin": "^1.31.18",
     "axios": "^1.6.5",
     "immer": "^10.0.3",
diff --git a/examples/react/kitchen-sink-react-query/package.json b/examples/react/kitchen-sink-react-query/package.json
index 4275826c6..2170ec6bb 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.17.8",
     "@tanstack/react-query-devtools": "^5.17.8",
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "axios": "^1.6.5",
     "immer": "^10.0.3",
     "react": "^18.2.0",
diff --git a/examples/react/kitchen-sink/package.json b/examples/react/kitchen-sink/package.json
index 1d0ef9687..5a37caeb8 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.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "axios": "^1.6.5",
     "immer": "^10.0.3",
     "react": "^18.2.0",
diff --git a/examples/react/large-file-based/package.json b/examples/react/large-file-based/package.json
index 8c542343d..ed195ac8b 100644
--- a/examples/react/large-file-based/package.json
+++ b/examples/react/large-file-based/package.json
@@ -11,8 +11,8 @@
     "test:types": "tsc --extendedDiagnostics"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "@tanstack/router-vite-plugin": "^1.31.18",
     "axios": "^1.6.5",
     "immer": "^10.0.3",
diff --git a/examples/react/large-file-based/src/routes/absolute.tsx b/examples/react/large-file-based/src/routes/absolute.tsx
index 9d20c3398..ba1f87505 100644
--- a/examples/react/large-file-based/src/routes/absolute.tsx
+++ b/examples/react/large-file-based/src/routes/absolute.tsx
@@ -1,5 +1,5 @@
 import * as React from 'react'
-import { createFileRoute, Link } from '@tanstack/react-router'
+import { Link, createFileRoute } from '@tanstack/react-router'
 
 export const Route = createFileRoute('/absolute')({
   component: AbsoluteComponent,
diff --git a/examples/react/large-file-based/src/routes/relative.tsx b/examples/react/large-file-based/src/routes/relative.tsx
index b7c36d926..6f6e581ef 100644
--- a/examples/react/large-file-based/src/routes/relative.tsx
+++ b/examples/react/large-file-based/src/routes/relative.tsx
@@ -1,5 +1,5 @@
 import * as React from 'react'
-import { createFileRoute, Link } from '@tanstack/react-router'
+import { Link, createFileRoute } from '@tanstack/react-router'
 
 export const Route = createFileRoute('/relative')({
   component: RelativeComponent,
diff --git a/examples/react/location-masking/package.json b/examples/react/location-masking/package.json
index af1f1a520..2a98d37d7 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.0.5",
     "@tanstack/react-query": "^5.17.8",
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "axios": "^1.6.5",
     "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 4d7b5f2d6..35e66961f 100644
--- a/examples/react/navigation-blocking/package.json
+++ b/examples/react/navigation-blocking/package.json
@@ -10,8 +10,8 @@
   },
   "dependencies": {
     "@tanstack/react-query": "^5.17.8",
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "axios": "^1.6.5",
     "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 51b8b0f15..bde65fde1 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.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "@tanstack/router-vite-plugin": "^1.31.18",
     "axios": "^1.6.5",
     "immer": "^10.0.3",
diff --git a/examples/react/quickstart/package.json b/examples/react/quickstart/package.json
index 581c8bf9b..97ed8146c 100644
--- a/examples/react/quickstart/package.json
+++ b/examples/react/quickstart/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "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 79862c1a8..6d88192c1 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.31.19",
+    "@tanstack/react-router": "^1.31.23",
     "@tanstack/react-virtual": "^3.0.1",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/router-devtools": "^1.31.23",
     "react": "^18.2.0",
     "react-dom": "^18.2.0"
   },
diff --git a/examples/react/vinxi-basic-ssr-streaming/package.json b/examples/react/vinxi-basic-ssr-streaming/package.json
index 9895e4101..c6cea9ea0 100644
--- a/examples/react/vinxi-basic-ssr-streaming/package.json
+++ b/examples/react/vinxi-basic-ssr-streaming/package.json
@@ -8,9 +8,9 @@
     "start": "vinxi start"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/react-router-server": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/react-router-server": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "@vinxi/react": "0.2.2",
     "@vinxi/server-functions": "^0.3.2",
     "autoprefixer": "^10.4.19",
@@ -20,7 +20,7 @@
     "vinxi": "^0.3.11"
   },
   "devDependencies": {
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/router-devtools": "^1.31.23",
     "@tanstack/router-vite-plugin": "^1.31.18",
     "@types/react": "^18.2.47",
     "@types/react-dom": "^18.2.18",
diff --git a/examples/react/vinxi-basic-ssr/package.json b/examples/react/vinxi-basic-ssr/package.json
index a681345eb..eb7a40eec 100644
--- a/examples/react/vinxi-basic-ssr/package.json
+++ b/examples/react/vinxi-basic-ssr/package.json
@@ -8,8 +8,8 @@
     "start": "vinxi start"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/react-router-server": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/react-router-server": "^1.31.23",
     "@vinxi/react": "0.1.1",
     "@vinxi/server-functions": "^0.1.1",
     "autoprefixer": "^10.4.15",
@@ -18,7 +18,7 @@
     "vinxi": "0.1.2"
   },
   "devDependencies": {
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/router-devtools": "^1.31.23",
     "@tanstack/router-vite-plugin": "^1.31.18",
     "@types/react": "^18.2.47",
     "@types/react-dom": "^18.2.18",
diff --git a/examples/react/vinxi-basic/package.json b/examples/react/vinxi-basic/package.json
index 738a59563..c595c1b76 100644
--- a/examples/react/vinxi-basic/package.json
+++ b/examples/react/vinxi-basic/package.json
@@ -8,8 +8,8 @@
     "start": "vinxi start"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/react-router-server": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/react-router-server": "^1.31.23",
     "@vinxi/react": "0.1.1",
     "@vinxi/server-functions": "^0.1.1",
     "autoprefixer": "^10.4.15",
@@ -18,7 +18,7 @@
     "vinxi": "0.1.2"
   },
   "devDependencies": {
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/router-devtools": "^1.31.23",
     "@tanstack/router-vite-plugin": "^1.31.18",
     "@types/react": "^18.2.47",
     "@types/react-dom": "^18.2.18",
diff --git a/examples/react/wip-trpc-react-query/package.json b/examples/react/wip-trpc-react-query/package.json
index 79db9750b..49a95ea53 100644
--- a/examples/react/wip-trpc-react-query/package.json
+++ b/examples/react/wip-trpc-react-query/package.json
@@ -13,8 +13,8 @@
   "dependencies": {
     "@tanstack/react-query": "^4.36.1",
     "@tanstack/react-query-devtools": "^4.36.1",
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "@trpc/client": "^10.45.0",
     "@trpc/react-query": "^10.45.0",
     "@trpc/server": "^10.45.0",
diff --git a/examples/react/wip-waku-rsc/package.json b/examples/react/wip-waku-rsc/package.json
index f3d01263b..509b982ec 100644
--- a/examples/react/wip-waku-rsc/package.json
+++ b/examples/react/wip-waku-rsc/package.json
@@ -10,8 +10,8 @@
   },
   "dependencies": {
     "@hono/node-server": "^1.4.1",
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "hono": "^3.12.0",
     "react": "18.3.0-canary-0cdfef19b-20231211",
     "react-dom": "18.3.0-canary-0cdfef19b-20231211",
diff --git a/examples/react/wip-with-bling/package.json b/examples/react/wip-with-bling/package.json
index 26913745b..a75a2ad66 100644
--- a/examples/react/wip-with-bling/package.json
+++ b/examples/react/wip-with-bling/package.json
@@ -13,10 +13,10 @@
   },
   "dependencies": {
     "@tanstack/bling": "^0.5.0",
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/react-router-server": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/react-router-server": "^1.31.23",
     "@tanstack/react-store": "^0.2.1",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/router-devtools": "^1.31.23",
     "axios": "^1.6.5",
     "fastify": "^4.25.2",
     "get-port": "^7.0.0",
diff --git a/examples/react/wip-with-bling/server.js b/examples/react/wip-with-bling/server.js
index a8084b94d..a82f6dd8a 100644
--- a/examples/react/wip-with-bling/server.js
+++ b/examples/react/wip-with-bling/server.js
@@ -126,7 +126,7 @@ export async function createServer(
         if (!isProd) {
           return vite.ssrLoadModule('/src/entry-server.tsx')
         } else {
-          return import('./dist/server/entry-server.tsx')
+          return import('./dist/server/entry-server.js')
         }
       })()
 
diff --git a/examples/react/wip-with-framer-motion/package.json b/examples/react/wip-with-framer-motion/package.json
index 4096be4a2..0412a982d 100644
--- a/examples/react/wip-with-framer-motion/package.json
+++ b/examples/react/wip-with-framer-motion/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "axios": "^1.6.5",
     "framer-motion": "^10.17.9",
     "immer": "^10.0.3",
diff --git a/examples/react/with-trpc/package.json b/examples/react/with-trpc/package.json
index 692b14963..c64a27194 100644
--- a/examples/react/with-trpc/package.json
+++ b/examples/react/with-trpc/package.json
@@ -13,8 +13,8 @@
   "dependencies": {
     "@tanstack/react-query": "^4.36.1",
     "@tanstack/react-query-devtools": "^4.36.1",
-    "@tanstack/react-router": "^1.31.19",
-    "@tanstack/router-devtools": "^1.31.19",
+    "@tanstack/react-router": "^1.31.23",
+    "@tanstack/router-devtools": "^1.31.23",
     "@trpc/client": "^10.45.0",
     "@trpc/react-query": "^10.45.0",
     "@trpc/server": "^10.45.0",
diff --git a/packages/react-router-server/package.json b/packages/react-router-server/package.json
index 31dd074bc..0328ebd58 100644
--- a/packages/react-router-server/package.json
+++ b/packages/react-router-server/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/react-router-server",
-  "version": "1.31.19",
+  "version": "1.31.23",
   "description": "",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/react-router-server/src/client/Meta.tsx b/packages/react-router-server/src/client/Meta.tsx
index c8067896c..a6e204758 100644
--- a/packages/react-router-server/src/client/Meta.tsx
+++ b/packages/react-router-server/src/client/Meta.tsx
@@ -1,9 +1,11 @@
-import { useRouter, useRouterState } from '@tanstack/react-router'
+import { createPortal } from 'react-dom'
+import { rootRouteId, useRouter, useRouterState } from '@tanstack/react-router'
 import * as React from 'react'
 import { Asset } from './Asset'
+import type { RootRouteOptions } from '@tanstack/react-router'
 import type { RouterManagedTag } from './RouterManagedTag'
 
-export const Meta = () => {
+export const useMeta = () => {
   const router = useRouter()
 
   const routeMeta = useRouterState({
@@ -81,17 +83,78 @@ export const Meta = () => {
       }
     }) ?? []
 
-  const allMeta = [
-    ...meta,
-    ...links,
-    ...manifestMeta,
-  ] as Array<RouterManagedTag>
+  return [...meta, ...links, ...manifestMeta] as Array<RouterManagedTag>
+}
 
-  return (
+export const useMetaElements = () => {
+  const router = useRouter()
+  const meta = useMeta()
+  const MetaComponent = (
+    router.looseRoutesById[rootRouteId]!.options as RootRouteOptions
+  ).metaComponent
+
+  const metaElements = (
     <>
-      {allMeta.map((asset, i) => (
+      {router.isServer ? <meta name="tsr-meta" /> : null}
+      {meta.map((asset, i) => (
         <Asset {...asset} key={`tsr-meta-${asset.tag}-${i}`} />
       ))}
+      {router.isServer ? <meta name="/tsr-meta" /> : null}
     </>
   )
+
+  return MetaComponent ? (
+    <MetaComponent>{metaElements}</MetaComponent>
+  ) : (
+    metaElements
+  )
+}
+
+/**
+ * @description The `Meta` component is used to render meta tags and links for the current route.
+ * It should be rendered in the `<head>` of your document. If you are using React 18, this will
+ * likely be in your `rootRoute.shellComponent` option. If you are using React 19, this can be
+ * rendered anywhere in your __root route's component.
+ */
+export const Meta = () => {
+  return useMetaElements()
+}
+
+/**
+ *
+ * @deprecated DO NOT USE THIS COMPONENT.
+ * This component is used internally by <StartClient /> and will be removed in a future release.
+ */
+export const ClientMeta = () => {
+  const metaElements = useMetaElements()
+  const [mounted, setMounted] = React.useState(false)
+
+  React[
+    typeof document !== 'undefined' ? 'useLayoutEffect' : 'useEffect'
+  ](() => {
+    // Remove all meta between the tsr meta tags
+    const start = document.head.querySelector('meta[name="tsr-meta"]')
+    const end = document.head.querySelector('meta[name="/tsr-meta"]')
+
+    // Iterate over all head children and remove them until we reach the end
+    let current = start?.nextElementSibling
+    while (current && current !== end) {
+      const next = current.nextElementSibling
+      current.remove()
+      current = next
+    }
+
+    // Remove the markers
+    start?.remove()
+    end?.remove()
+
+    setMounted(true)
+  }, [])
+
+  if (!mounted) {
+    return null
+  }
+
+  // Only render this on the client, using a portal
+  return createPortal(metaElements, document.head)
 }
diff --git a/packages/react-router-server/src/client/StartClient.tsx b/packages/react-router-server/src/client/StartClient.tsx
index 808591e10..9d425830a 100644
--- a/packages/react-router-server/src/client/StartClient.tsx
+++ b/packages/react-router-server/src/client/StartClient.tsx
@@ -1,11 +1,25 @@
-import { RouterProvider } from '@tanstack/react-router'
+import {
+  RouterContextProvider,
+  RouterProvider,
+  rootRouteId,
+} from '@tanstack/react-router'
 import * as React from 'react'
-import type { AnyRouter } from '@tanstack/react-router'
+import { ClientMeta } from './Meta'
+import type { AnyRouter, RootRouteOptions } from '@tanstack/react-router'
 
 export function StartClient(props: { router: AnyRouter }) {
   if (!props.router.state.matches.length) {
     props.router.hydrate()
   }
 
-  return <RouterProvider router={props.router} />
+  const ShellComponent = (
+    props.router.looseRoutesById[rootRouteId]?.options as RootRouteOptions
+  ).shellComponent
+
+  return (
+    <RouterContextProvider router={props.router}>
+      {ShellComponent ? <ClientMeta /> : null}
+      <RouterProvider router={props.router} />
+    </RouterContextProvider>
+  )
 }
diff --git a/packages/react-router-server/src/client/index.tsx b/packages/react-router-server/src/client/index.tsx
index 37bc8908f..692f33546 100644
--- a/packages/react-router-server/src/client/index.tsx
+++ b/packages/react-router-server/src/client/index.tsx
@@ -14,7 +14,7 @@ export {
 } from './createServerFn'
 export { DehydrateRouter } from './DehydrateRouter'
 export { json } from './json'
-export { Meta } from './Meta'
+export { Meta, ClientMeta } from './Meta'
 export { type RouterManagedTag } from './RouterManagedTag'
 export { Scripts } from './Scripts'
 export { StartClient } from './StartClient'
diff --git a/packages/react-router-server/src/server/StartServer.tsx b/packages/react-router-server/src/server/StartServer.tsx
index 113199417..9b7fa463f 100644
--- a/packages/react-router-server/src/server/StartServer.tsx
+++ b/packages/react-router-server/src/server/StartServer.tsx
@@ -5,6 +5,7 @@ import {
   rootRouteId,
 } from '@tanstack/react-router'
 import * as React from 'react'
+import { ClientMeta } from '../client'
 import type { RootRouteOptions } from '../../../react-router/dist/esm/route'
 import type { AnyRouter } from '@tanstack/react-router'
 
@@ -25,20 +26,25 @@ export function StartServer<TRouter extends AnyRouter>(props: {
     props.router.looseRoutesById[rootRouteId]?.options as RootRouteOptions
   ).shellComponent
 
+  const client = (
+    <>
+      {ShellComponent ? <ClientMeta /> : null}
+      <Matches />
+    </>
+  )
+
+  const shell = ShellComponent ? (
+    <ShellComponent>
+      <div id="root">{client}</div>
+    </ShellComponent>
+  ) : (
+    client
+  )
+
   return (
-    // Provide the hydration context still, since `<DehydrateRouter />` needs it.
     <hydrationContext.Provider value={hydrationCtxValue}>
-      {/* We also render the shell here */}
       <RouterContextProvider router={props.router}>
-        {ShellComponent ? (
-          <ShellComponent>
-            <div id="root">
-              <Matches />
-            </div>
-          </ShellComponent>
-        ) : (
-          <Matches />
-        )}
+        {shell}
       </RouterContextProvider>
     </hydrationContext.Provider>
   )
diff --git a/packages/react-router/package.json b/packages/react-router/package.json
index 5194ffb51..e5016c93b 100644
--- a/packages/react-router/package.json
+++ b/packages/react-router/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/react-router",
-  "version": "1.31.19",
+  "version": "1.31.23",
   "description": "",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/react-router/src/Matches.tsx b/packages/react-router/src/Matches.tsx
index 794932b76..86aa41ca5 100644
--- a/packages/react-router/src/Matches.tsx
+++ b/packages/react-router/src/Matches.tsx
@@ -8,6 +8,7 @@ import { createControlledPromise, pick } from './utils'
 import { CatchNotFound, DefaultGlobalNotFound, isNotFound } from './not-found'
 import { isRedirect } from './redirects'
 import { type AnyRouter, type RegisteredRouter } from './router'
+import { Transitioner } from './Transitioner'
 import type { ResolveRelativePath, ToOptions } from './link'
 import type { AnyRoute, ReactNode, StaticDataRouteOption } from './route'
 import type {
@@ -99,6 +100,21 @@ export type AnyRouteMatch = RouteMatch<any, any, any, any, any, any, any>
 export function Matches() {
   const router = useRouter()
 
+  const inner = (
+    <>
+      <MatchesInner />
+      <Transitioner />
+    </>
+  )
+
+  return router.options.InnerWrap ? (
+    <router.options.InnerWrap>{inner}</router.options.InnerWrap>
+  ) : (
+    inner
+  )
+}
+
+function MatchesInner() {
   const matchId = useRouterState({
     select: (s) => {
       return s.matches[0]?.id
@@ -109,7 +125,7 @@ export function Matches() {
     select: (s) => s.resolvedLocation.state.key!,
   })
 
-  const inner = (
+  return (
     <matchContext.Provider value={matchId}>
       <CatchBoundary
         getResetKey={() => resetKey}
@@ -126,12 +142,6 @@ export function Matches() {
       </CatchBoundary>
     </matchContext.Provider>
   )
-
-  return router.options.InnerWrap ? (
-    <router.options.InnerWrap>{inner}</router.options.InnerWrap>
-  ) : (
-    inner
-  )
 }
 
 function SafeFragment(props: any) {
diff --git a/packages/react-router/src/RouterProvider.tsx b/packages/react-router/src/RouterProvider.tsx
index d8745a9c0..73a113dec 100644
--- a/packages/react-router/src/RouterProvider.tsx
+++ b/packages/react-router/src/RouterProvider.tsx
@@ -1,10 +1,8 @@
+// eslint-disable-next-line @typescript-eslint/consistent-type-imports
 import * as React from 'react'
-import { flushSync } from 'react-dom'
 import { Matches } from './Matches'
-import { pick, useLayoutEffect } from './utils'
-import { useRouter } from './useRouter'
-import { useRouterState } from './useRouterState'
 import { getRouterContext } from './routerContext'
+import { Transitioner } from './Transitioner'
 import type { NavigateOptions, ToOptions } from './link'
 import type { ParsedLocation } from './location'
 import type { AnyRoute } from './route'
@@ -87,17 +85,11 @@ export function RouterContextProvider<
 
   const routerContext = getRouterContext()
 
-  const pendingElement = router.options.defaultPendingComponent ? (
-    <router.options.defaultPendingComponent />
-  ) : null
-
   const provider = (
-    <React.Suspense fallback={pendingElement}>
-      <routerContext.Provider value={router}>
-        {children}
-        <Transitioner />
-      </routerContext.Provider>
-    </React.Suspense>
+    <routerContext.Provider value={router}>
+      {children}
+      <Transitioner />
+    </routerContext.Provider>
   )
 
   if (router.options.Wrap) {
@@ -118,129 +110,6 @@ export function RouterProvider<
   )
 }
 
-function Transitioner() {
-  const router = useRouter()
-  const mountLoadForRouter = React.useRef({ router, mounted: false })
-  const routerState = useRouterState({
-    select: (s) =>
-      pick(s, ['isLoading', 'location', 'resolvedLocation', 'isTransitioning']),
-  })
-
-  const [isTransitioning, startReactTransition_] = React.useTransition()
-  // Track pending state changes
-  const hasPendingMatches = useRouterState({
-    select: (s) => s.matches.some((d) => d.status === 'pending'),
-  })
-
-  const previousIsLoading = usePrevious(routerState.isLoading)
-
-  const isAnyPending =
-    routerState.isLoading || isTransitioning || hasPendingMatches
-  const previousIsAnyPending = usePrevious(isAnyPending)
-
-  router.startReactTransition = startReactTransition_
-
-  const tryLoad = async () => {
-    try {
-      await router.load()
-    } catch (err) {
-      console.error(err)
-    }
-  }
-
-  // Subscribe to location changes
-  // and try to load the new location
-  useLayoutEffect(() => {
-    const unsub = router.history.subscribe(router.load)
-
-    const nextLocation = router.buildLocation({
-      to: router.latestLocation.pathname,
-      search: true,
-      params: true,
-      hash: true,
-      state: true,
-    })
-
-    if (routerState.location.href !== nextLocation.href) {
-      router.commitLocation({ ...nextLocation, replace: true })
-    }
-
-    return () => {
-      unsub()
-    }
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [router, router.history])
-
-  // Try to load the initial location
-  useLayoutEffect(() => {
-    if (
-      window.__TSR_DEHYDRATED__ ||
-      (mountLoadForRouter.current.router === router &&
-        mountLoadForRouter.current.mounted)
-    ) {
-      return
-    }
-    mountLoadForRouter.current = { router, mounted: true }
-    tryLoad()
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [router])
-
-  useLayoutEffect(() => {
-    // The router was loading and now it's not
-    if (previousIsLoading && !routerState.isLoading) {
-      const toLocation = router.state.location
-      const fromLocation = router.state.resolvedLocation
-      const pathChanged = fromLocation.href !== toLocation.href
-
-      router.emit({
-        type: 'onLoad',
-        fromLocation,
-        toLocation,
-        pathChanged,
-      })
-
-      // if (router.viewTransitionPromise) {
-      //   console.log('resolving view transition promise')
-      // }
-
-      // router.viewTransitionPromise?.resolve(true)
-    }
-  }, [previousIsLoading, router, routerState.isLoading])
-
-  useLayoutEffect(() => {
-    // The router was pending and now it's not
-    if (previousIsAnyPending && !isAnyPending) {
-      const toLocation = router.state.location
-      const fromLocation = router.state.resolvedLocation
-      const pathChanged = fromLocation.href !== toLocation.href
-
-      router.emit({
-        type: 'onResolved',
-        fromLocation,
-        toLocation,
-        pathChanged,
-      })
-
-      router.__store.setState((s) => ({
-        ...s,
-        status: 'idle',
-        resolvedLocation: s.location,
-      }))
-
-      if ((document as any).querySelector) {
-        if (router.state.location.hash !== '') {
-          const el = document.getElementById(router.state.location.hash)
-          if (el) {
-            el.scrollIntoView()
-          }
-        }
-      }
-    }
-  }, [isAnyPending, previousIsAnyPending, router])
-
-  return null
-}
-
 export function getRouteMatch<TRouteTree extends AnyRoute>(
   state: RouterState<TRouteTree>,
   id: string,
@@ -275,15 +144,3 @@ export type RouterProps<
     >['context']
   >
 }
-
-function usePrevious<T>(value: T): T {
-  const ref = React.useRef<T>(value)
-
-  if (ref.current !== value) {
-    const prevValue = ref.current
-    ref.current = value
-    return prevValue
-  } else {
-    return ref.current
-  }
-}
diff --git a/packages/react-router/src/Transitioner.tsx b/packages/react-router/src/Transitioner.tsx
new file mode 100644
index 000000000..d1132db57
--- /dev/null
+++ b/packages/react-router/src/Transitioner.tsx
@@ -0,0 +1,126 @@
+import * as React from 'react'
+import { pick, useLayoutEffect, usePrevious } from './utils'
+import { useRouter } from './useRouter'
+import { useRouterState } from './useRouterState'
+
+export function Transitioner() {
+  const router = useRouter()
+  const mountLoadForRouter = React.useRef({ router, mounted: false })
+  const routerState = useRouterState({
+    select: (s) =>
+      pick(s, ['isLoading', 'location', 'resolvedLocation', 'isTransitioning']),
+  })
+
+  const [isTransitioning, startReactTransition_] = React.useTransition()
+  // Track pending state changes
+  const hasPendingMatches = useRouterState({
+    select: (s) => s.matches.some((d) => d.status === 'pending'),
+  })
+
+  const previousIsLoading = usePrevious(routerState.isLoading)
+
+  const isAnyPending =
+    routerState.isLoading || isTransitioning || hasPendingMatches
+  const previousIsAnyPending = usePrevious(isAnyPending)
+
+  router.startReactTransition = startReactTransition_
+
+  const tryLoad = async () => {
+    try {
+      await router.load()
+    } catch (err) {
+      console.error(err)
+    }
+  }
+
+  // Subscribe to location changes
+  // and try to load the new location
+  useLayoutEffect(() => {
+    const unsub = router.history.subscribe(router.load)
+
+    const nextLocation = router.buildLocation({
+      to: router.latestLocation.pathname,
+      search: true,
+      params: true,
+      hash: true,
+      state: true,
+    })
+
+    if (routerState.location.href !== nextLocation.href) {
+      router.commitLocation({ ...nextLocation, replace: true })
+    }
+
+    return () => {
+      unsub()
+    }
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [router, router.history])
+
+  // Try to load the initial location
+  useLayoutEffect(() => {
+    if (
+      window.__TSR_DEHYDRATED__ ||
+      (mountLoadForRouter.current.router === router &&
+        mountLoadForRouter.current.mounted)
+    ) {
+      return
+    }
+    mountLoadForRouter.current = { router, mounted: true }
+    tryLoad()
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [router])
+
+  useLayoutEffect(() => {
+    // The router was loading and now it's not
+    if (previousIsLoading && !routerState.isLoading) {
+      const toLocation = router.state.location
+      const fromLocation = router.state.resolvedLocation
+      const pathChanged = fromLocation.href !== toLocation.href
+
+      router.emit({
+        type: 'onLoad',
+        fromLocation,
+        toLocation,
+        pathChanged,
+      })
+
+      // if (router.viewTransitionPromise) {
+      //   console.log('resolving view transition promise')
+      // }
+      // router.viewTransitionPromise?.resolve(true)
+    }
+  }, [previousIsLoading, router, routerState.isLoading])
+
+  useLayoutEffect(() => {
+    // The router was pending and now it's not
+    if (previousIsAnyPending && !isAnyPending) {
+      const toLocation = router.state.location
+      const fromLocation = router.state.resolvedLocation
+      const pathChanged = fromLocation.href !== toLocation.href
+
+      router.emit({
+        type: 'onResolved',
+        fromLocation,
+        toLocation,
+        pathChanged,
+      })
+
+      router.__store.setState((s) => ({
+        ...s,
+        status: 'idle',
+        resolvedLocation: s.location,
+      }))
+
+      if ((document as any).querySelector) {
+        if (router.state.location.hash !== '') {
+          const el = document.getElementById(router.state.location.hash)
+          if (el) {
+            el.scrollIntoView()
+          }
+        }
+      }
+    }
+  }, [isAnyPending, previousIsAnyPending, router])
+
+  return null
+}
diff --git a/packages/react-router/src/awaited.tsx b/packages/react-router/src/awaited.tsx
index 6393eef63..f5c8208fd 100644
--- a/packages/react-router/src/awaited.tsx
+++ b/packages/react-router/src/awaited.tsx
@@ -59,14 +59,15 @@ export function useAwaited<T>({ promise }: AwaitOptions<T>): [T] {
   // If we are the originator of the promise,
   // inject the state into the HTML stream
   if (!isDehydratedDeferred(promise)) {
-    router.injectHtml(`<script class='tsr_deferred_data'>window.__TSR__DEFERRED__${state.uid} = ${JSON.stringify(router.options.transformer.stringify(state))}</script>
-<script class='tsr_deferred_data'>
+    router.injectHtml(
+      `<script class='tsr_deferred_data'>window.__TSR__DEFERRED__${state.uid} = ${JSON.stringify(router.options.transformer.stringify(state))}
   if (window.__TSR__ROUTER__) {
-    let deferred = window.__TSR__ROUTER__.getDeferred('${state.uid}')
-    if (deferred) deferred.resolve(window.__TSR__DEFERRED__${state.uid})
+    let deferred = window.__TSR__ROUTER__.getDeferred('${state.uid}');
+    if (deferred) deferred.resolve(window.__TSR__DEFERRED__${state.uid});
   }
-  document.querySelectorAll('.tsr_deferred_data').forEach((el) => el.parentElement.removeChild(el))
-</script>`)
+  document.querySelectorAll('.tsr_deferred_data').forEach((el) => el.parentElement.removeChild(el));
+</script>`,
+    )
   }
 
   if (state.status === 'error') {
diff --git a/packages/react-router/src/index.tsx b/packages/react-router/src/index.tsx
index d002cd4fa..2e647a257 100644
--- a/packages/react-router/src/index.tsx
+++ b/packages/react-router/src/index.tsx
@@ -181,6 +181,7 @@ export {
   type TrimPath,
   type TrimPathLeft,
   type TrimPathRight,
+  type RootRouteOptions,
 } from './route'
 export {
   type ParseRoute,
diff --git a/packages/react-router/src/route.ts b/packages/react-router/src/route.ts
index 5808da4a0..611a64a50 100644
--- a/packages/react-router/src/route.ts
+++ b/packages/react-router/src/route.ts
@@ -271,6 +271,7 @@ export type UpdatableRouteOptions<
   onStay?: (match: TRouteMatch) => void
   onLeave?: (match: TRouteMatch) => void
   meta?: (ctx: {
+    matches: Array<TRouteMatch>
     params: TAllParams
     loaderData: TLoaderData
   }) => Array<JSX.IntrinsicElements['meta']>
@@ -1036,6 +1037,13 @@ export type RootRouteOptions<
    * and client-side rendering. When 19 is released, this prop will be deprecated.
    */
   shellComponent?: (props: { children: React.ReactNode }) => JSX.Element
+  /**
+   * @description It's suggested to first use the `meta` option in the root route and sub routes to
+   * add meta tags. However, it may not be possible to add all types of meta tags using the `meta` option, like
+   * "base", for example, or you may want to read from router state/context to conditionally add meta tags in a
+   * component context.
+   **/
+  metaComponent?: (props: { children: React.ReactNode }) => JSX.Element
 }
 
 export function createRootRouteWithContext<TRouterContext extends {}>() {
diff --git a/packages/react-router/src/router.ts b/packages/react-router/src/router.ts
index 32c2d785c..bf8ebe1b6 100644
--- a/packages/react-router/src/router.ts
+++ b/packages/react-router/src/router.ts
@@ -877,6 +877,7 @@ export class Router<
       // due to being stale
       if (match.status === 'success') {
         match.meta = route.options.meta?.({
+          matches,
           params: match.params,
           loaderData: match.loaderData,
         })
@@ -1721,6 +1722,7 @@ export class Router<
                     checkLatest()
 
                     const meta = route.options.meta?.({
+                      matches,
                       params: match.params,
                       loaderData,
                     })
@@ -2141,7 +2143,7 @@ export class Router<
     const matches = this.matchRoutes(
       this.state.location.pathname,
       this.state.location.search,
-    ).map((match) => {
+    ).map((match, i, allMatches) => {
       const dehydratedMatch = dehydratedState.dehydratedMatches.find(
         (d) => d.id === match.id,
       )
@@ -2159,6 +2161,7 @@ export class Router<
           ? {}
           : {
               meta: route.options.meta?.({
+                matches: allMatches,
                 params: match.params,
                 loaderData: dehydratedMatch.loaderData,
               }),
diff --git a/packages/react-router/src/utils.ts b/packages/react-router/src/utils.ts
index 22b2bb3f1..7d8937287 100644
--- a/packages/react-router/src/utils.ts
+++ b/packages/react-router/src/utils.ts
@@ -138,10 +138,9 @@ export function replaceEqualDeep<T>(prev: any, _next: T): T {
     for (let i = 0; i < nextSize; i++) {
       const key = array ? i : nextItems[i]
       if (
-        !array &&
+        ((!array && prevItems.includes(key)) || array) &&
         prev[key] === undefined &&
-        next[key] === undefined &&
-        prevItems.includes(key)
+        next[key] === undefined
       ) {
         copy[key] = undefined
         equalItems++
@@ -353,3 +352,15 @@ export function removeLayoutSegments(routePath: string): string {
   const newSegments = segments.filter((segment) => !segment.startsWith('_'))
   return newSegments.join('/')
 }
+
+export function usePrevious<T>(value: T): T {
+  const ref = React.useRef<T>(value)
+
+  if (ref.current !== value) {
+    const prevValue = ref.current
+    ref.current = value
+    return prevValue
+  } else {
+    return ref.current
+  }
+}
diff --git a/packages/router-devtools/package.json b/packages/router-devtools/package.json
index ec7869683..585cddc67 100644
--- a/packages/router-devtools/package.json
+++ b/packages/router-devtools/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/router-devtools",
-  "version": "1.31.19",
+  "version": "1.31.23",
   "description": "",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0a33c7102..04abf6325 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -93,10 +93,10 @@ importers:
   examples/react/authenticated-routes:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@tanstack/router-vite-plugin':
         specifier: ^1.31.18
@@ -136,10 +136,10 @@ importers:
         specifier: ^5.17.8
         version: 5.17.8(react@18.2.0)
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       axios:
         specifier: ^1.6.5
@@ -170,10 +170,10 @@ importers:
         specifier: ^5.17.8
         version: 5.17.8(react@18.2.0)
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       axios:
         specifier: ^1.6.5
@@ -204,10 +204,10 @@ importers:
   examples/react/basic-file-based:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@tanstack/router-vite-plugin':
         specifier: ^1.31.18
@@ -244,10 +244,10 @@ importers:
   examples/react/basic-file-based-codesplitting:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@tanstack/router-vite-plugin':
         specifier: ^1.31.18
@@ -290,10 +290,10 @@ importers:
         specifier: ^5.17.8
         version: 5.17.8(@tanstack/react-query@5.17.8)(react@18.2.0)
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       axios:
         specifier: ^1.6.5
@@ -327,10 +327,10 @@ importers:
         specifier: ^5.17.8
         version: 5.17.8(@tanstack/react-query@5.17.8)(react@18.2.0)
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@tanstack/router-vite-plugin':
         specifier: ^1.31.18
@@ -367,13 +367,13 @@ importers:
   examples/react/basic-ssr-file-based:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/react-router-server':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router-server
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@tanstack/router-vite-plugin':
         specifier: ^1.31.18
@@ -431,13 +431,13 @@ importers:
   examples/react/basic-ssr-streaming-file-based:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/react-router-server':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router-server
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@tanstack/router-vite-plugin':
         specifier: ^1.31.18
@@ -498,10 +498,10 @@ importers:
   examples/react/deferred-data:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       axios:
         specifier: ^1.6.5
@@ -535,10 +535,10 @@ importers:
   examples/react/kitchen-sink:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       axios:
         specifier: ^1.6.5
@@ -572,10 +572,10 @@ importers:
   examples/react/kitchen-sink-file-based:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@tanstack/router-vite-plugin':
         specifier: ^1.31.18
@@ -618,10 +618,10 @@ importers:
         specifier: ^5.17.8
         version: 5.17.8(@tanstack/react-query@5.17.8)(react@18.2.0)
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       axios:
         specifier: ^1.6.5
@@ -661,10 +661,10 @@ importers:
         specifier: ^5.17.8
         version: 5.17.8(@tanstack/react-query@5.17.8)(react@18.2.0)
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@tanstack/router-vite-plugin':
         specifier: ^1.31.18
@@ -701,10 +701,10 @@ importers:
   examples/react/large-file-based:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@tanstack/router-vite-plugin':
         specifier: ^1.31.18
@@ -747,10 +747,10 @@ importers:
         specifier: ^5.17.8
         version: 5.17.8(react@18.2.0)
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       axios:
         specifier: ^1.6.5
@@ -781,10 +781,10 @@ importers:
         specifier: ^5.17.8
         version: 5.17.8(react@18.2.0)
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       axios:
         specifier: ^1.6.5
@@ -812,10 +812,10 @@ importers:
   examples/react/quickstart:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       react:
         specifier: ^18.2.0
@@ -840,10 +840,10 @@ importers:
   examples/react/quickstart-file-based:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@tanstack/router-vite-plugin':
         specifier: ^1.31.18
@@ -880,13 +880,13 @@ importers:
   examples/react/scroll-restoration:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/react-virtual':
         specifier: ^3.0.1
         version: 3.0.1(react-dom@18.2.0)(react@18.2.0)
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       react:
         specifier: ^18.2.0
@@ -911,10 +911,10 @@ importers:
   examples/react/vinxi-basic:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/react-router-server':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router-server
       '@vinxi/react':
         specifier: 0.1.1
@@ -936,7 +936,7 @@ importers:
         version: 0.1.2(@types/node@20.11.10)(preact@10.19.3)(rollup@4.14.3)
     devDependencies:
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@tanstack/router-vite-plugin':
         specifier: ^1.31.18
@@ -954,10 +954,10 @@ importers:
   examples/react/vinxi-basic-ssr:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/react-router-server':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router-server
       '@vinxi/react':
         specifier: 0.1.1
@@ -979,7 +979,7 @@ importers:
         version: 0.1.2(@types/node@20.11.10)(preact@10.19.3)(rollup@4.14.3)
     devDependencies:
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@tanstack/router-vite-plugin':
         specifier: ^1.31.18
@@ -997,13 +997,13 @@ importers:
   examples/react/vinxi-basic-ssr-streaming:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/react-router-server':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router-server
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@vinxi/react':
         specifier: 0.2.2
@@ -1049,10 +1049,10 @@ importers:
         specifier: ^4.36.1
         version: 4.36.1(@tanstack/react-query@4.36.1)(react-dom@18.2.0)(react@18.2.0)
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@trpc/client':
         specifier: ^10.45.0
@@ -1110,10 +1110,10 @@ importers:
         specifier: ^1.4.1
         version: 1.4.1
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       hono:
         specifier: ^3.12.0
@@ -1156,16 +1156,16 @@ importers:
         specifier: ^0.5.0
         version: 0.5.0(vite@5.0.13)
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/react-router-server':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router-server
       '@tanstack/react-store':
         specifier: ^0.2.1
         version: 0.2.1(react-dom@18.3.0-canary-ab31a9ed2-20230824)(react@18.3.0-canary-ab31a9ed2-20230824)
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       axios:
         specifier: ^1.6.5
@@ -1235,10 +1235,10 @@ importers:
   examples/react/wip-with-framer-motion:
     dependencies:
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       axios:
         specifier: ^1.6.5
@@ -1281,10 +1281,10 @@ importers:
         specifier: ^4.36.1
         version: 4.36.1(@tanstack/react-query@4.36.1)(react-dom@18.2.0)(react@18.2.0)
       '@tanstack/react-router':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/react-router
       '@tanstack/router-devtools':
-        specifier: ^1.31.19
+        specifier: ^1.31.23
         version: link:../../../packages/router-devtools
       '@trpc/client':
         specifier: ^10.45.0


Test patch:
diff --git a/packages/react-router/tests/utils.test.ts b/packages/react-router/tests/utils.test.ts
index 5504c5cbd..e882233ab 100644
--- a/packages/react-router/tests/utils.test.ts
+++ b/packages/react-router/tests/utils.test.ts
@@ -1,10 +1,10 @@
-import { describe, it, expect } from 'vitest'
+import { describe, expect, it } from 'vitest'
 import {
   exactPathTest,
   isPlainArray,
+  removeLayoutSegments,
   removeTrailingSlash,
   replaceEqualDeep,
-  removeLayoutSegments,
 } from '../src/utils'
 
 describe('replaceEqualDeep', () => {
@@ -280,6 +280,20 @@ describe('replaceEqualDeep', () => {
 
     expect(current).toBe(next)
   })
+
+  it('should return the previous value when both values are an array of undefined', () => {
+    const current = [undefined]
+    const next = replaceEqualDeep(current, [undefined])
+
+    expect(next).toBe(current)
+  })
+
+  it('should return the previous value when both values are an array that contains undefined', () => {
+    const current = [{ foo: 1 }, undefined]
+    const next = replaceEqualDeep(current, [{ foo: 1 }, undefined])
+
+    expect(next).toBe(current)
+  })
 })
 
 describe('isPlainArray', () => {