Repository: TanStack/router
Pull request #2548 (2024-10-15 16:46:55)

docs: update nested routes comparison
Next.js' nested layouts are still far from being considered true first-class nested routes.

https://github.com/vercel/next.js/issues/44793#issuecomment-1634211402


Patch:
diff --git a/docs/eslint/create-route-property-order.md b/docs/eslint/create-route-property-order.md
index 28d00fb67..56f27821f 100644
--- a/docs/eslint/create-route-property-order.md
+++ b/docs/eslint/create-route-property-order.md
@@ -10,14 +10,14 @@ For the following functions, the property order of the passed in object matters
 - `createRootRoute`
 - `createRootRouteWithContext`
 
-The correct property order is as follows:
+The correct property order is as follows
 
-- `params`
-- `validateSearch`
-- `loaderDeps`
+- `params`, `validateSearch`
+- `loaderDeps`, `search.middlewares`
 - `context`
 - `beforeLoad`
 - `loader`
+- `onEnter`, `onStay`, `onLeave`, `meta`, `links`, `scripts`, `headers`
 
 All other properties are insensitive to the order as they do not depend on type inference.
 
diff --git a/docs/framework/react/api/router/RouterOptionsType.md b/docs/framework/react/api/router/RouterOptionsType.md
index 2625db731..2b1a41f0e 100644
--- a/docs/framework/react/api/router/RouterOptionsType.md
+++ b/docs/framework/react/api/router/RouterOptionsType.md
@@ -35,6 +35,15 @@ The `RouterOptions` type accepts an object with the following properties and met
 - A function that will be used to parse search params when parsing the current location.
 - Defaults to `defaultParseSearch`.
 
+### `search.strict` property
+
+- Type: `boolean`
+- Optional
+- Defaults to `false`
+- Configures how unknown search params (= not returned by any `validateSearch`) are treated.
+- If `false`, unknown search params will be kept.
+- If `true`, unknown search params will be removed.
+
 ### `defaultPreload` property
 
 - Type: `undefined | false | 'intent' | 'viewport'`
diff --git a/docs/framework/react/api/router/RouterType.md b/docs/framework/react/api/router/RouterType.md
index 7b79451c6..8cc148557 100644
--- a/docs/framework/react/api/router/RouterType.md
+++ b/docs/framework/react/api/router/RouterType.md
@@ -129,10 +129,12 @@ Navigates to a new location.
 
 ### `.invalidate` method
 
-Invalidates all route matches by forcing their `beforeLoad` and `load` functions to be called again.
+Invalidates route matches by forcing their `beforeLoad` and `load` functions to be called again.
 
-- Type: `() => Promise<void>`
+- Type: `(opts?: {filter?: (d: MakeRouteMatch<TRouteTree>) => boolean}) => Promise<void>`
 - This is useful any time your loader data might be out of date or stale. For example, if you have a route that displays a list of posts, and you have a loader function that fetches the list of posts from an API, you might want to invalidate the route matches for that route any time a new post is created so that the list of posts is always up-to-date.
+- if `filter` is not supplied, all matches will be invalidated
+- if `filter` is supplied, only matches for which `filter` returns `true` will be invalidate.
 - You might also want to invalidate the Router if you imperatively `reset` the router's `CatchBoundary` to trigger loaders again.
 
 ### `.load` method
diff --git a/docs/framework/react/api/router/retainSearchParams.md b/docs/framework/react/api/router/retainSearchParams.md
index 474c03182..b0ac8175d 100644
--- a/docs/framework/react/api/router/retainSearchParams.md
+++ b/docs/framework/react/api/router/retainSearchParams.md
@@ -7,9 +7,10 @@ title: Search middleware to retain search params
 
 ## retainSearchParams props
 
-The `retainSearchParams` accepts a list of keys of those search params that shall be retained.
+The `retainSearchParams` either accepts `true` or a list of keys of those search params that shall be retained.
+If `true` is passed in, all search params will be retained.
 
-## Example
+## Examples
 
 ```tsx
 import { z } from 'zod'
@@ -27,3 +28,21 @@ export const Route = createRootRoute({
   },
 })
 ```
+
+```tsx
+import { z } from 'zod'
+import { createFileRoute } from '@tanstack/react-router'
+import { zodSearchValidator } from '@tanstack/router-zod-adapter'
+
+const searchSchema = z.object({
+  one: z.string().optional(),
+  two: z.string().optional(),
+})
+
+export const Route = createFileRoute('/hello')({
+  validateSearch: zodSearchValidator(searchSchema),
+  search: {
+    middlewares: [retainSearchParams(true)],
+  },
+})
+```
diff --git a/docs/framework/react/comparison.md b/docs/framework/react/comparison.md
index 56ba0e41c..6911492a5 100644
--- a/docs/framework/react/comparison.md
+++ b/docs/framework/react/comparison.md
@@ -20,7 +20,7 @@ Feature/Capability Key:
 | Github Repo / Stars                            | [![][stars-tanstack-router]][gh-tanstack-router] | [![][stars-router]][gh-router]                        | [![][stars-nextjs]][gh-nextjs]                        |
 | Bundle Size                                    | [![][bp-tanstack-router]][bpl-tanstack-router]   | [![][bp-router]][bpl-router]                          | ❓                                                    |
 | History, Memory & Hash Routers                 | ✅                                               | ✅                                                    | 🛑                                                    |
-| Nested / Layout Routes                         | ✅                                               | ✅                                                    | ✅                                                    |
+| Nested / Layout Routes                         | ✅                                               | ✅                                                    | 🟡                                                    |
 | Suspense-like Route Transitions                | ✅                                               | ✅                                                    | ✅                                                    |
 | Typesafe Routes                                | ✅                                               | 🛑                                                    | 🟡                                                    |
 | Code-based Routes                              | ✅                                               | ✅                                                    | 🛑                                                    |
diff --git a/docs/framework/react/start/api-routes.md b/docs/framework/react/start/api-routes.md
index 7d298b6f2..3dd077af9 100644
--- a/docs/framework/react/start/api-routes.md
+++ b/docs/framework/react/start/api-routes.md
@@ -236,19 +236,19 @@ You can set the status code of the response by either:
   })
   ```
 
-- Using the `setStatus` helper function from `vinxi/http`
+- Using the `setResponseStatus` helper function from `vinxi/http`
 
   ```ts
   // routes/api/hello.ts
   import { json } from '@tanstack/start'
   import { createAPIFileRoute } from '@tanstack/start/api'
-  import { setStatus } from 'vinxi/http'
+  import { setResponseStatus } from 'vinxi/http'
 
   export const Route = createAPIFileRoute('/users/$id')({
     GET: async ({ request, params }) => {
       const user = await findUser(params.id)
       if (!user) {
-        setStatus(404)
+        setResponseStatus(404)
         return new Response('User not found')
       }
       return json(user)
diff --git a/docs/framework/react/start/server-functions.md b/docs/framework/react/start/server-functions.md
index 4a1d412b2..70ea8e62c 100644
--- a/docs/framework/react/start/server-functions.md
+++ b/docs/framework/react/start/server-functions.md
@@ -245,14 +245,14 @@ export const getServerTime = createServerFn('GET', async () => {
 
 ## Responding with Custom Status Codes
 
-To respond with a custom status code, you can use Vinxi's `setStatus` function:
+To respond with a custom status code, you can use Vinxi's `setResponseStatus` function:
 
 ```tsx
 import { createServerFn } from '@tanstack/start'
-import { setStatus } from 'vinxi/http'
+import { setResponseStatus } from 'vinxi/http'
 
 export const getServerTime = createServerFn('GET', async () => {
-  setStatus(201)
+  setResponseStatus(201)
   return new Date().toISOString()
 })
 ```
diff --git a/examples/react/authenticated-routes/package.json b/examples/react/authenticated-routes/package.json
index 8a41b648a..5a27105d6 100644
--- a/examples/react/authenticated-routes/package.json
+++ b/examples/react/authenticated-routes/package.json
@@ -9,9 +9,9 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "redaxios": "^0.5.1",
diff --git a/examples/react/basic-default-search-params/package.json b/examples/react/basic-default-search-params/package.json
index eeff05d0b..02b16779e 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.59.13",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
     "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 512a01222..2bea3520e 100644
--- a/examples/react/basic-file-based-codesplitting/package.json
+++ b/examples/react/basic-file-based-codesplitting/package.json
@@ -9,9 +9,9 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "redaxios": "^0.5.1",
diff --git a/examples/react/basic-file-based/package.json b/examples/react/basic-file-based/package.json
index e10bcc0d0..e97676faf 100644
--- a/examples/react/basic-file-based/package.json
+++ b/examples/react/basic-file-based/package.json
@@ -9,9 +9,9 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "redaxios": "^0.5.1",
diff --git a/examples/react/basic-react-query-file-based/package.json b/examples/react/basic-react-query-file-based/package.json
index 3902438a8..df0f98908 100644
--- a/examples/react/basic-react-query-file-based/package.json
+++ b/examples/react/basic-react-query-file-based/package.json
@@ -11,9 +11,9 @@
   "dependencies": {
     "@tanstack/react-query": "^5.59.13",
     "@tanstack/react-query-devtools": "^5.59.13",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "redaxios": "^0.5.1",
diff --git a/examples/react/basic-react-query/package.json b/examples/react/basic-react-query/package.json
index 7763e452e..35f4695e4 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.59.13",
     "@tanstack/react-query-devtools": "^5.59.13",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
     "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 d216677fb..dabbbe3b6 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.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
-    "@tanstack/start": "^1.68.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
+    "@tanstack/start": "^1.70.0",
     "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 999c08809..8113d7012 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.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
-    "@tanstack/start": "^1.68.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
+    "@tanstack/start": "^1.70.0",
     "get-port": "^7.1.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
diff --git a/examples/react/basic-virtual-file-based/package.json b/examples/react/basic-virtual-file-based/package.json
index eccf317be..7dedd942a 100644
--- a/examples/react/basic-virtual-file-based/package.json
+++ b/examples/react/basic-virtual-file-based/package.json
@@ -9,9 +9,9 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
     "@tanstack/virtual-file-routes": "^1.64.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
diff --git a/examples/react/basic-virtual-inside-file-based/package.json b/examples/react/basic-virtual-inside-file-based/package.json
index f87c124f8..d00b2a083 100644
--- a/examples/react/basic-virtual-inside-file-based/package.json
+++ b/examples/react/basic-virtual-inside-file-based/package.json
@@ -9,9 +9,9 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
     "@tanstack/virtual-file-routes": "^1.64.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 3534bbc14..6c788b1ef 100644
--- a/examples/react/basic/package.json
+++ b/examples/react/basic/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
     "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 2966813aa..d9c487826 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.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
     "redaxios": "^0.5.1",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
diff --git a/examples/react/kitchen-sink-file-based/package.json b/examples/react/kitchen-sink-file-based/package.json
index 8194a4ae2..a8ca42798 100644
--- a/examples/react/kitchen-sink-file-based/package.json
+++ b/examples/react/kitchen-sink-file-based/package.json
@@ -9,9 +9,9 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
     "immer": "^10.1.1",
     "react": "^18.2.0",
     "react-dom": "^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 9342d18ec..138fa27b4 100644
--- a/examples/react/kitchen-sink-react-query-file-based/package.json
+++ b/examples/react/kitchen-sink-react-query-file-based/package.json
@@ -11,9 +11,9 @@
   "dependencies": {
     "@tanstack/react-query": "^5.59.13",
     "@tanstack/react-query-devtools": "^5.59.13",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
     "immer": "^10.1.1",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
diff --git a/examples/react/kitchen-sink-react-query/package.json b/examples/react/kitchen-sink-react-query/package.json
index 2efdb0b21..91125ca68 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.59.13",
     "@tanstack/react-query-devtools": "^5.59.13",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
     "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 313896fa9..003a785c7 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.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
     "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 ce2dcca75..afd3cc7ff 100644
--- a/examples/react/large-file-based/package.json
+++ b/examples/react/large-file-based/package.json
@@ -12,9 +12,9 @@
   },
   "dependencies": {
     "@tanstack/react-query": "^5.59.13",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "redaxios": "^0.5.1",
diff --git a/examples/react/location-masking/package.json b/examples/react/location-masking/package.json
index dadfbc3fc..f6a1dd284 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.2",
     "@tanstack/react-query": "^5.59.13",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
     "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 48187b231..e9e1c8809 100644
--- a/examples/react/navigation-blocking/package.json
+++ b/examples/react/navigation-blocking/package.json
@@ -10,8 +10,8 @@
   },
   "dependencies": {
     "@tanstack/react-query": "^5.59.13",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
     "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 b521f4dc5..793353921 100644
--- a/examples/react/quickstart-file-based/package.json
+++ b/examples/react/quickstart-file-based/package.json
@@ -9,9 +9,9 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "redaxios": "^0.5.1",
diff --git a/examples/react/quickstart-rspack-file-based/package.json b/examples/react/quickstart-rspack-file-based/package.json
index bbcc9dec6..58d71c4d7 100644
--- a/examples/react/quickstart-rspack-file-based/package.json
+++ b/examples/react/quickstart-rspack-file-based/package.json
@@ -8,15 +8,15 @@
     "preview": "rsbuild preview"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
     "react": "^18.3.1",
     "react-dom": "^18.3.1"
   },
   "devDependencies": {
     "@rsbuild/core": "1.0.13",
     "@rsbuild/plugin-react": "1.0.3",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/router-plugin": "^1.69.1",
     "@types/react": "^18.3.3",
     "@types/react-dom": "^18.3.0",
     "typescript": "^5.6.2"
diff --git a/examples/react/quickstart-webpack-file-based/package.json b/examples/react/quickstart-webpack-file-based/package.json
index 591134544..adbc2f78e 100644
--- a/examples/react/quickstart-webpack-file-based/package.json
+++ b/examples/react/quickstart-webpack-file-based/package.json
@@ -7,14 +7,14 @@
     "build": "webpack build && tsc --noEmit"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
     "react": "^18.3.1",
     "react-dom": "^18.3.1"
   },
   "devDependencies": {
     "@swc/core": "^1.7.35",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/router-plugin": "^1.69.1",
     "@types/react": "^18.3.3",
     "@types/react-dom": "^18.3.0",
     "html-webpack-plugin": "^5.6.0",
diff --git a/examples/react/quickstart/package.json b/examples/react/quickstart/package.json
index 398752498..263e754cb 100644
--- a/examples/react/quickstart/package.json
+++ b/examples/react/quickstart/package.json
@@ -9,8 +9,8 @@
     "start": "vite"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
     "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 7489ef652..4d5b9a3b5 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.67.0",
+    "@tanstack/react-router": "^1.70.0",
     "@tanstack/react-virtual": "^3.10.8",
-    "@tanstack/router-devtools": "^1.67.0",
+    "@tanstack/router-devtools": "^1.70.0",
     "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 879a52431..f8a73341e 100644
--- a/examples/react/search-validator-adapters/package.json
+++ b/examples/react/search-validator-adapters/package.json
@@ -10,12 +10,12 @@
   },
   "dependencies": {
     "@tanstack/react-query": "^5.59.13",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-arktype-adapter": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
-    "@tanstack/router-valibot-adapter": "^1.67.0",
-    "@tanstack/router-zod-adapter": "^1.67.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-arktype-adapter": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
+    "@tanstack/router-valibot-adapter": "^1.70.0",
+    "@tanstack/router-zod-adapter": "^1.70.0",
     "arktype": "^2.0.0-rc.15",
     "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 b9e41f731..53376b689 100644
--- a/examples/react/start-basic-auth/package.json
+++ b/examples/react/start-basic-auth/package.json
@@ -11,9 +11,9 @@
   },
   "dependencies": {
     "@prisma/client": "5.20.0",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/start": "^1.68.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/start": "^1.70.0",
     "dotenv": "^16.4.5",
     "prisma": "^5.20.0",
     "react": "^18.3.1",
diff --git a/examples/react/start-basic-react-query/package.json b/examples/react/start-basic-react-query/package.json
index 469daa682..12dba97e2 100644
--- a/examples/react/start-basic-react-query/package.json
+++ b/examples/react/start-basic-react-query/package.json
@@ -11,10 +11,10 @@
   "dependencies": {
     "@tanstack/react-query": "^5.59.13",
     "@tanstack/react-query-devtools": "^5.59.13",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/react-router-with-query": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/start": "^1.68.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/react-router-with-query": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/start": "^1.70.0",
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
     "redaxios": "^0.5.1",
diff --git a/examples/react/start-basic-rsc/package.json b/examples/react/start-basic-rsc/package.json
index 72a7bf911..a42d0858c 100644
--- a/examples/react/start-basic-rsc/package.json
+++ b/examples/react/start-basic-rsc/package.json
@@ -10,9 +10,9 @@
   },
   "dependencies": {
     "@babel/plugin-syntax-typescript": "^7.25.7",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/start": "^1.68.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/start": "^1.70.0",
     "redaxios": "^0.5.1",
     "tailwind-merge": "^2.5.3",
     "vinxi": "0.4.3"
diff --git a/examples/react/start-basic/package.json b/examples/react/start-basic/package.json
index 6b9822f9c..dbcd32281 100644
--- a/examples/react/start-basic/package.json
+++ b/examples/react/start-basic/package.json
@@ -9,9 +9,9 @@
     "start": "vinxi start"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/start": "^1.68.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/start": "^1.70.0",
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
     "redaxios": "^0.5.1",
diff --git a/examples/react/start-clerk-basic/package.json b/examples/react/start-clerk-basic/package.json
index f0bbc6077..8dd93742f 100644
--- a/examples/react/start-clerk-basic/package.json
+++ b/examples/react/start-clerk-basic/package.json
@@ -10,9 +10,9 @@
   },
   "dependencies": {
     "@clerk/tanstack-start": "0.4.12",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/start": "^1.68.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/start": "^1.70.0",
     "dotenv": "^16.4.5",
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
diff --git a/examples/react/start-convex-trellaux/convex/_generated/api.d.ts b/examples/react/start-convex-trellaux/convex/_generated/api.d.ts
index 615831974..33b400c93 100644
--- a/examples/react/start-convex-trellaux/convex/_generated/api.d.ts
+++ b/examples/react/start-convex-trellaux/convex/_generated/api.d.ts
@@ -1,3 +1,5 @@
+/* prettier-ignore-start */
+
 /* eslint-disable */
 /**
  * Generated `api` utility.
@@ -34,3 +36,5 @@ export declare const internal: FilterApi<
   typeof fullApi,
   FunctionReference<any, 'internal'>
 >
+
+/* prettier-ignore-end */
diff --git a/examples/react/start-convex-trellaux/convex/_generated/api.js b/examples/react/start-convex-trellaux/convex/_generated/api.js
index 2b62e6b82..f5eb6204e 100644
--- a/examples/react/start-convex-trellaux/convex/_generated/api.js
+++ b/examples/react/start-convex-trellaux/convex/_generated/api.js
@@ -1,3 +1,5 @@
+/* prettier-ignore-start */
+
 /* eslint-disable */
 /**
  * Generated `api` utility.
@@ -20,3 +22,5 @@ import { anyApi } from 'convex/server'
  */
 export const api = anyApi
 export const internal = anyApi
+
+/* prettier-ignore-end */
diff --git a/examples/react/start-convex-trellaux/convex/_generated/dataModel.d.ts b/examples/react/start-convex-trellaux/convex/_generated/dataModel.d.ts
index 5b936a43a..45f90d64e 100644
--- a/examples/react/start-convex-trellaux/convex/_generated/dataModel.d.ts
+++ b/examples/react/start-convex-trellaux/convex/_generated/dataModel.d.ts
@@ -1,3 +1,5 @@
+/* prettier-ignore-start */
+
 /* eslint-disable */
 /**
  * Generated data model types.
@@ -58,3 +60,5 @@ export type Id<TableName extends TableNames | SystemTableNames> =
  * `mutationGeneric` to make them type-safe.
  */
 export type DataModel = DataModelFromSchemaDefinition<typeof schema>
+
+/* prettier-ignore-end */
diff --git a/examples/react/start-convex-trellaux/convex/_generated/server.d.ts b/examples/react/start-convex-trellaux/convex/_generated/server.d.ts
index 869a677bc..ffdf9e04e 100644
--- a/examples/react/start-convex-trellaux/convex/_generated/server.d.ts
+++ b/examples/react/start-convex-trellaux/convex/_generated/server.d.ts
@@ -1,3 +1,5 @@
+/* prettier-ignore-start */
+
 /* eslint-disable */
 /**
  * Generated utilities for implementing server-side Convex query and mutation functions.
@@ -140,3 +142,5 @@ export type DatabaseReader = GenericDatabaseReader<DataModel>
  * for the guarantees Convex provides your functions.
  */
 export type DatabaseWriter = GenericDatabaseWriter<DataModel>
+
+/* prettier-ignore-end */
diff --git a/examples/react/start-convex-trellaux/convex/_generated/server.js b/examples/react/start-convex-trellaux/convex/_generated/server.js
index d16f9527d..a557aec2c 100644
--- a/examples/react/start-convex-trellaux/convex/_generated/server.js
+++ b/examples/react/start-convex-trellaux/convex/_generated/server.js
@@ -1,3 +1,5 @@
+/* prettier-ignore-start */
+
 /* eslint-disable */
 /**
  * Generated utilities for implementing server-side Convex query and mutation functions.
@@ -87,3 +89,5 @@ export const internalAction = internalActionGeneric
  * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
  */
 export const httpAction = httpActionGeneric
+
+/* prettier-ignore-end */
diff --git a/examples/react/start-convex-trellaux/package.json b/examples/react/start-convex-trellaux/package.json
index 8b1c41b53..bfe988c0f 100644
--- a/examples/react/start-convex-trellaux/package.json
+++ b/examples/react/start-convex-trellaux/package.json
@@ -13,10 +13,10 @@
   "dependencies": {
     "@tanstack/react-query": "^5.59.13",
     "@tanstack/react-query-devtools": "^5.59.13",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/react-router-with-query": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/start": "^1.68.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/react-router-with-query": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/start": "^1.70.0",
     "@convex-dev/react-query": "0.0.0-alpha.5",
     "concurrently": "^8.2.2",
     "convex": "^1.16.5",
diff --git a/examples/react/start-counter/package.json b/examples/react/start-counter/package.json
index a254c1bdb..bd0a29f78 100644
--- a/examples/react/start-counter/package.json
+++ b/examples/react/start-counter/package.json
@@ -9,8 +9,8 @@
     "start": "vinxi start"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/start": "^1.68.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/start": "^1.70.0",
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
     "vinxi": "0.4.3"
diff --git a/examples/react/start-supabase-basic/package.json b/examples/react/start-supabase-basic/package.json
index 4cf6534ac..ce6039811 100644
--- a/examples/react/start-supabase-basic/package.json
+++ b/examples/react/start-supabase-basic/package.json
@@ -15,9 +15,9 @@
   "dependencies": {
     "@supabase/ssr": "^0.5.1",
     "@supabase/supabase-js": "^2.45.4",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/start": "^1.68.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/start": "^1.70.0",
     "@vitejs/plugin-react": "^4.3.2",
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
diff --git a/examples/react/start-trellaux/package.json b/examples/react/start-trellaux/package.json
index 898c8795c..d521dce8d 100644
--- a/examples/react/start-trellaux/package.json
+++ b/examples/react/start-trellaux/package.json
@@ -11,10 +11,10 @@
   "dependencies": {
     "@tanstack/react-query": "^5.59.13",
     "@tanstack/react-query-devtools": "^5.59.13",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/react-router-with-query": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/start": "^1.68.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/react-router-with-query": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/start": "^1.70.0",
     "ky": "^1.7.2",
     "msw": "^2.4.11",
     "react": "^18.3.1",
diff --git a/examples/react/with-framer-motion/package.json b/examples/react/with-framer-motion/package.json
index 9638cb977..4bfb90b81 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.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
     "redaxios": "^0.5.1",
     "framer-motion": "^11.11.8",
     "react": "^18.2.0",
diff --git a/examples/react/with-trpc-react-query/package.json b/examples/react/with-trpc-react-query/package.json
index fb6141e87..a9bbfe4b0 100644
--- a/examples/react/with-trpc-react-query/package.json
+++ b/examples/react/with-trpc-react-query/package.json
@@ -10,9 +10,9 @@
   "dependencies": {
     "@tanstack/react-query": "^5.59.13",
     "@tanstack/react-query-devtools": "^5.59.13",
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
     "@trpc/client": "11.0.0-rc.571",
     "@trpc/react-query": "11.0.0-rc.571",
     "@trpc/server": "11.0.0-rc.571",
diff --git a/examples/react/with-trpc/package.json b/examples/react/with-trpc/package.json
index 8345fdda2..00516aac1 100644
--- a/examples/react/with-trpc/package.json
+++ b/examples/react/with-trpc/package.json
@@ -8,9 +8,9 @@
     "start": "vinxi start"
   },
   "dependencies": {
-    "@tanstack/react-router": "^1.67.0",
-    "@tanstack/router-devtools": "^1.67.0",
-    "@tanstack/router-plugin": "^1.66.1",
+    "@tanstack/react-router": "^1.70.0",
+    "@tanstack/router-devtools": "^1.70.0",
+    "@tanstack/router-plugin": "^1.69.1",
     "@trpc/client": "11.0.0-rc.571",
     "@trpc/server": "11.0.0-rc.571",
     "react": "^18.2.0",
diff --git a/packages/create-router/package.json b/packages/create-router/package.json
index b27ea986c..f577012b5 100644
--- a/packages/create-router/package.json
+++ b/packages/create-router/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/create-router",
-  "version": "1.67.0",
+  "version": "1.70.0",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/eslint-plugin-router/package.json b/packages/eslint-plugin-router/package.json
index 1b44e1456..b09785482 100644
--- a/packages/eslint-plugin-router/package.json
+++ b/packages/eslint-plugin-router/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/eslint-plugin-router",
-  "version": "1.66.1",
+  "version": "1.70.0",
   "description": "ESLint plugin for TanStack Router",
   "author": "Manuel Schiller",
   "license": "MIT",
diff --git a/packages/eslint-plugin-router/src/rules/create-route-property-order/constants.ts b/packages/eslint-plugin-router/src/rules/create-route-property-order/constants.ts
index 74885cd10..1bcd28257 100644
--- a/packages/eslint-plugin-router/src/rules/create-route-property-order/constants.ts
+++ b/packages/eslint-plugin-router/src/rules/create-route-property-order/constants.ts
@@ -1,3 +1,5 @@
+import { getCheckedProperties } from './create-route-property-order.utils'
+
 export const createRouteFunctionsIndirect = [
   'createFileRoute',
   'createRootRouteWithContext',
@@ -14,18 +16,17 @@ export const createRouteFunctions = [
 
 export type CreateRouteFunction = (typeof createRouteFunctions)[number]
 
-export const checkedProperties = [
-  'params',
-  'validateSearch',
-  'loaderDeps',
-  'context',
-  'beforeLoad',
-  'loader',
-] as const
-
 export const sortRules = [
-  [['params', 'validateSearch'], ['loaderDeps']],
+  [['params', 'validateSearch'], ['search']],
+  [['search'], ['loaderDeps']],
   [['loaderDeps'], ['context']],
   [['context'], ['beforeLoad']],
   [['beforeLoad'], ['loader']],
+  [
+    ['loader'],
+    ['onEnter', 'onStay', 'onLeave', 'meta', 'links', 'scripts', 'headers'],
+  ],
 ] as const
+
+export type CheckedProperties = (typeof sortRules)[number][number][number]
+export const checkedProperties = getCheckedProperties(sortRules)
diff --git a/packages/eslint-plugin-router/src/rules/create-route-property-order/create-route-property-order.utils.ts b/packages/eslint-plugin-router/src/rules/create-route-property-order/create-route-property-order.utils.ts
index 390c703e8..87891e7ab 100644
--- a/packages/eslint-plugin-router/src/rules/create-route-property-order/create-route-property-order.utils.ts
+++ b/packages/eslint-plugin-router/src/rules/create-route-property-order/create-route-property-order.utils.ts
@@ -65,3 +65,9 @@ export function sortDataByOrder<T, TKey extends keyof T>(
   }
   return result
 }
+
+export function getCheckedProperties<T>(
+  orderRules: ReadonlyArray<ReadonlyArray<ReadonlyArray<T>>>,
+): ReadonlyArray<T> {
+  return [...new Set<T>(orderRules.flat(2))]
+}
diff --git a/packages/react-router-with-query/package.json b/packages/react-router-with-query/package.json
index 4b3bb1cf8..974868265 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.67.0",
+  "version": "1.70.0",
   "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 fb0c8e159..57dd098c6 100644
--- a/packages/react-router/package.json
+++ b/packages/react-router/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/react-router",
-  "version": "1.67.0",
+  "version": "1.70.0",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/react-router/src/Matches.tsx b/packages/react-router/src/Matches.tsx
index 8736c0244..36dc9ae25 100644
--- a/packages/react-router/src/Matches.tsx
+++ b/packages/react-router/src/Matches.tsx
@@ -142,7 +142,6 @@ export interface RouteMatch<
   paramsError: unknown
   searchError: unknown
   updatedAt: number
-  componentsPromise?: Promise<Array<void>>
   loadPromise?: ControlledPromise<void>
   beforeLoadPromise?: ControlledPromise<void>
   loaderPromise?: ControlledPromise<void>
diff --git a/packages/react-router/src/Transitioner.tsx b/packages/react-router/src/Transitioner.tsx
index 88189592b..f3d3d3f4e 100644
--- a/packages/react-router/src/Transitioner.tsx
+++ b/packages/react-router/src/Transitioner.tsx
@@ -39,6 +39,7 @@ export function Transitioner() {
       params: true,
       hash: true,
       state: true,
+      _includeValidateSearch: true,
     })
 
     if (
diff --git a/packages/react-router/src/fileRoute.ts b/packages/react-router/src/fileRoute.ts
index e84814b41..8962278a0 100644
--- a/packages/react-router/src/fileRoute.ts
+++ b/packages/react-router/src/fileRoute.ts
@@ -265,16 +265,9 @@ export function createLazyRoute<
   }
 }
 
-const routeGroupPatternRegex = /\(.+\)/g
-
-function removeGroups(s: string) {
-  return s.replaceAll(routeGroupPatternRegex, '').replaceAll('//', '/')
-}
-
 export function createLazyFileRoute<
   TFilePath extends keyof FileRoutesByPath,
   TRoute extends FileRoutesByPath[TFilePath]['preLoaderRoute'],
 >(id: TFilePath) {
-  return (opts: LazyRouteOptions) =>
-    new LazyRoute<TRoute>({ id: removeGroups(id), ...opts })
+  return (opts: LazyRouteOptions) => new LazyRoute<TRoute>({ id, ...opts })
 }
diff --git a/packages/react-router/src/route.ts b/packages/react-router/src/route.ts
index 4129444c2..60ca66c61 100644
--- a/packages/react-router/src/route.ts
+++ b/packages/react-router/src/route.ts
@@ -945,6 +945,7 @@ export class Route<
   rank!: number
   lazyFn?: () => Promise<LazyRoute<any>>
   _lazyPromise?: Promise<void>
+  _componentsPromise?: Promise<Array<void>>
 
   /**
    * @deprecated Use the `createRoute` function instead.
diff --git a/packages/react-router/src/router.ts b/packages/react-router/src/router.ts
index 09450a689..66e12a7ca 100644
--- a/packages/react-router/src/router.ts
+++ b/packages/react-router/src/router.ts
@@ -447,11 +447,21 @@ export interface RouterOptions<
    * While usually automatic, sometimes it can be useful to force the router into a server-side state, e.g. when using the router in a non-browser environment that has access to a global.document object.
    *
    * @default typeof document !== 'undefined'
-   * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#isserver property)
+   * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#isserver-property)
    */
   isServer?: boolean
 
   defaultSsr?: boolean
+
+  search?: {
+    /**
+     * Configures how unknown search params (= not returned by any `validateSearch`) are treated.
+     *
+     * @default false
+     * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#search.strict-property)
+     */
+    strict?: boolean
+  }
 }
 
 export interface RouterErrorSerializer<TSerializedError> {
@@ -1511,6 +1521,7 @@ export class Router<
       let search = applyMiddlewares()
 
       if (opts._includeValidateSearch) {
+        let validatedSearch = this.options.search?.strict ? {} : search
         matchedRoutesResult?.matchedRoutes.forEach((route) => {
           try {
             if (route.options.validateSearch) {
@@ -1518,12 +1529,16 @@ export class Router<
                 typeof route.options.validateSearch === 'object'
                   ? route.options.validateSearch.parse
                   : route.options.validateSearch
-              search = { ...search, ...validator(search) }
+              validatedSearch = {
+                ...validatedSearch,
+                ...validator({ ...validatedSearch, ...search }),
+              }
             }
           } catch (e) {
             // ignore errors here because they are already handled in matchRoutes
           }
         })
+        search = validatedSearch
       }
       search = replaceEqualDeep(fromSearch, search)
       const searchStr = this.options.stringifySearch(search)
@@ -2336,37 +2351,41 @@ export class Router<
 
                         // Actually run the loader and handle the result
                         try {
-                          route._lazyPromise =
-                            route._lazyPromise ||
-                            (route.lazyFn
-                              ? route.lazyFn().then((lazyRoute) => {
-                                  const { id, ...options } = lazyRoute.options
+                          if (route._lazyPromise === undefined) {
+                            if (route.lazyFn) {
+                              route._lazyPromise = route
+                                .lazyFn()
+                                .then((lazyRoute) => {
+                                  // explicitly don't copy over the lazy route's id
+                                  const { id: _id, ...options } =
+                                    lazyRoute.options
                                   Object.assign(route.options, options)
                                 })
-                              : Promise.resolve())
+                            } else {
+                              route._lazyPromise = Promise.resolve()
+                            }
+                          }
 
                           // If for some reason lazy resolves more lazy components...
                           // We'll wait for that before pre attempt to preload any
                           // components themselves.
-                          const componentsPromise =
-                            this.getMatch(matchId)!.componentsPromise ||
-                            route._lazyPromise.then(() =>
-                              Promise.all(
-                                componentTypes.map(async (type) => {
-                                  const component = route.options[type]
-
-                                  if ((component as any)?.preload) {
-                                    await (component as any).preload()
-                                  }
-                                }),
-                              ),
+                          if (route._componentsPromise === undefined) {
+                            route._componentsPromise = route._lazyPromise.then(
+                              () =>
+                                Promise.all(
+                                  componentTypes.map(async (type) => {
+                                    const component = route.options[type]
+                                    if ((component as any)?.preload) {
+                                      await (component as any).preload()
+                                    }
+                                  }),
+                                ),
                             )
+                          }
 
-                          // Otherwise, load the route
                           updateMatch(matchId, (prev) => ({
                             ...prev,
                             isFetching: 'loader',
-                            componentsPromise,
                           }))
 
                           // Kick off the loader!
@@ -2442,9 +2461,9 @@ export class Router<
                           }))
                         }
 
-                        // Last but not least, wait for the the component
+                        // Last but not least, wait for the the components
                         // to be preloaded before we resolve the match
-                        await this.getMatch(matchId)!.componentsPromise
+                        await route._componentsPromise
                       } catch (err) {
                         handleRedirectAndNotFound(this.getMatch(matchId)!, err)
                       }
@@ -2505,14 +2524,21 @@ export class Router<
     return matches
   }
 
-  invalidate = () => {
-    const invalidate = (d: MakeRouteMatch<TRouteTree>) => ({
-      ...d,
-      invalid: true,
-      ...(d.status === 'error'
-        ? ({ status: 'pending', error: undefined } as const)
-        : {}),
-    })
+  invalidate = (opts?: {
+    filter?: (d: MakeRouteMatch<TRouteTree>) => boolean
+  }) => {
+    const invalidate = (d: MakeRouteMatch<TRouteTree>) => {
+      if (opts?.filter?.(d) ?? true) {
+        return {
+          ...d,
+          invalid: true,
+          ...(d.status === 'error'
+            ? ({ status: 'pending', error: undefined } as const)
+            : {}),
+        }
+      }
+      return d
+    }
 
     this.__store.setState((s) => ({
       ...s,
diff --git a/packages/react-router/src/searchMiddleware.ts b/packages/react-router/src/searchMiddleware.ts
index 7d561e7a6..dd0720a6a 100644
--- a/packages/react-router/src/searchMiddleware.ts
+++ b/packages/react-router/src/searchMiddleware.ts
@@ -1,10 +1,13 @@
 import type { SearchMiddleware } from './route'
 
 export function retainSearchParams<TSearchSchema extends object>(
-  keys: Array<keyof TSearchSchema>,
+  keys: Array<keyof TSearchSchema> | true,
 ): SearchMiddleware<TSearchSchema> {
   return ({ search, next }) => {
     const result = next(search)
+    if (keys === true) {
+      return { ...search, ...result }
+    }
     // add missing keys from search to result
     keys.forEach((key) => {
       if (!(key in result)) {
diff --git a/packages/router-arktype-adapter/package.json b/packages/router-arktype-adapter/package.json
index cfb7356b3..950fef3b6 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.67.0",
+  "version": "1.70.0",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/router-cli/package.json b/packages/router-cli/package.json
index 9e217706e..bfe5bb0ce 100644
--- a/packages/router-cli/package.json
+++ b/packages/router-cli/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/router-cli",
-  "version": "1.65.0",
+  "version": "1.69.1",
   "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 971f1aa4c..fc6347859 100644
--- a/packages/router-devtools/package.json
+++ b/packages/router-devtools/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/router-devtools",
-  "version": "1.67.0",
+  "version": "1.70.0",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/router-generator/package.json b/packages/router-generator/package.json
index 8d7328373..d7781f1fc 100644
--- a/packages/router-generator/package.json
+++ b/packages/router-generator/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/router-generator",
-  "version": "1.65.0",
+  "version": "1.69.1",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/router-generator/src/generator.ts b/packages/router-generator/src/generator.ts
index 1fbd17943..87fe699fc 100644
--- a/packages/router-generator/src/generator.ts
+++ b/packages/router-generator/src/generator.ts
@@ -591,12 +591,10 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
   interface FileRoutesByPath {
     ${routeNodes
       .map((routeNode) => {
-        const [filePathId, routeId] = getFilePathIdAndRouteIdFromPath(
-          routeNode.routePath,
-        )
+        const filePathId = getFilePathIdFromPath(routeNode.routePath)
 
         return `'${filePathId}': {
-          id: '${routeId}'
+          id: '${filePathId}'
           path: '${inferPath(routeNode)}'
           fullPath: '${inferFullPath(routeNode)}'
           preLoaderRoute: typeof ${routeNode.variableName}Import
@@ -661,24 +659,21 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
     const routesManifest = {
       __root__: {
         filePath: rootRouteNode.filePath,
-        children: routeTree.map(
-          (d) => getFilePathIdAndRouteIdFromPath(d.routePath)[1],
-        ),
+        children: routeTree.map((d) => getFilePathIdFromPath(d.routePath)),
       },
       ...Object.fromEntries(
         routeNodes.map((d) => {
-          const [_, routeId] = getFilePathIdAndRouteIdFromPath(d.routePath)
+          const filePathId = getFilePathIdFromPath(d.routePath)
 
           return [
-            routeId,
+            filePathId,
             {
               filePath: d.filePath,
               parent: d.parent?.routePath
-                ? getFilePathIdAndRouteIdFromPath(d.parent.routePath)[1]
+                ? getFilePathIdFromPath(d.parent.routePath)
                 : undefined,
-              children: d.children?.map(
-                (childRoute) =>
-                  getFilePathIdAndRouteIdFromPath(childRoute.routePath)[1],
+              children: d.children?.map((childRoute) =>
+                getFilePathIdFromPath(childRoute.routePath),
               ),
             },
           ]
@@ -749,12 +744,6 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
   )
 }
 
-function spaces(d: number): string {
-  return Array.from({ length: d })
-    .map(() => ' ')
-    .join('')
-}
-
 function removeTrailingUnderscores(s?: string) {
   return s?.replaceAll(/(_$)/gi, '').replaceAll(/(_\/)/gi, '/')
 }
@@ -879,7 +868,7 @@ export const createRouteNodesById = (
 ): Map<string, RouteNode> => {
   return new Map(
     routeNodes.map((routeNode) => {
-      const [_, id] = getFilePathIdAndRouteIdFromPath(routeNode.routePath)
+      const id = getFilePathIdFromPath(routeNode.routePath)
       return [id, routeNode]
     }),
   )
@@ -928,11 +917,9 @@ export const dedupeBranchesAndIndexRoutes = (
   })
 }
 
-function getFilePathIdAndRouteIdFromPath(pathname?: string) {
+function getFilePathIdFromPath(pathname?: string) {
   const filePathId = removeTrailingUnderscores(pathname)
-  const id = removeGroups(filePathId ?? '')
-
-  return [filePathId, id] as const
+  return filePathId ?? ''
 }
 
 function checkUnique<TElement>(routes: Array<TElement>, key: keyof TElement) {
diff --git a/packages/router-plugin/package.json b/packages/router-plugin/package.json
index 3665d03c1..a6971912c 100644
--- a/packages/router-plugin/package.json
+++ b/packages/router-plugin/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/router-plugin",
-  "version": "1.66.1",
+  "version": "1.69.1",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/router-valibot-adapter/package.json b/packages/router-valibot-adapter/package.json
index b80de6037..7ecea3fb1 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.67.0",
+  "version": "1.70.0",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/router-vite-plugin/package.json b/packages/router-vite-plugin/package.json
index d3a9318f5..4bd1afd31 100644
--- a/packages/router-vite-plugin/package.json
+++ b/packages/router-vite-plugin/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/router-vite-plugin",
-  "version": "1.66.1",
+  "version": "1.69.1",
   "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 82cb3e616..2e3cd167f 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.67.0",
+  "version": "1.70.0",
   "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 4f999fd85..e6ba996d5 100644
--- a/packages/start/package.json
+++ b/packages/start/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@tanstack/start",
-  "version": "1.68.0",
+  "version": "1.70.0",
   "description": "Modern and scalable routing for React applications",
   "author": "Tanner Linsley",
   "license": "MIT",
diff --git a/packages/start/src/server-handler/index.tsx b/packages/start/src/server-handler/index.tsx
index 955f2738c..17b585d06 100644
--- a/packages/start/src/server-handler/index.tsx
+++ b/packages/start/src/server-handler/index.tsx
@@ -5,7 +5,12 @@ import {
   isRedirect,
 } from '@tanstack/react-router'
 import invariant from 'tiny-invariant'
-import { eventHandler, toWebRequest } from 'vinxi/http'
+import {
+  eventHandler,
+  getEvent,
+  getResponseStatus,
+  toWebRequest,
+} from 'vinxi/http'
 import { getManifest } from 'vinxi/manifest'
 import {
   serverFnPayloadTypeHeader,
@@ -117,7 +122,7 @@ export async function handleServerRequest(request: Request, event?: H3Event) {
       return new Response(
         result !== undefined ? JSON.stringify(result) : undefined,
         {
-          status: 200,
+          status: getResponseStatus(getEvent()),
           headers: {
             'Content-Type': 'application/json',
             [serverFnReturnTypeHeader]: 'json',
@@ -143,7 +148,7 @@ export async function handleServerRequest(request: Request, event?: H3Event) {
       console.info()
 
       return new Response(JSON.stringify(error), {
-        status: 500,
+        status: getResponseStatus(getEvent()),
         headers: {
           'Content-Type': 'application/json',
           [serverFnReturnTypeHeader]: 'error',
@@ -155,10 +160,7 @@ export async function handleServerRequest(request: Request, event?: H3Event) {
   if (process.env.NODE_ENV === 'development')
     console.info(`ServerFn Response: ${response.status}`)
 
-  if (
-    response.status === 200 &&
-    response.headers.get('Content-Type') === 'application/json'
-  ) {
+  if (response.headers.get('Content-Type') === 'application/json') {
     const cloned = response.clone()
     const text = await cloned.text()
     const payload = text ? JSON.stringify(JSON.parse(text)) : 'undefined'
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8f41f62f8..89cbb17b9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -157,6 +157,9 @@ importers:
       '@tanstack/router-plugin':
         specifier: workspace:*
         version: link:../../../packages/router-plugin
+      '@tanstack/router-zod-adapter':
+        specifier: workspace:*
+        version: link:../../../packages/router-zod-adapter
       react:
         specifier: ^18.2.0
         version: 18.3.1
@@ -1575,10 +1578,10 @@ importers:
         version: 18.3.0
       html-webpack-plugin:
         specifier: ^5.6.0
-        version: 5.6.0(@rspack/core@1.0.10(@swc/helpers@0.5.13))(webpack@5.95.0)
+        version: 5.6.0(@rspack/core@1.0.10(@swc/helpers@0.5.13))(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4))
       swc-loader:
         specifier: ^0.2.6
-        version: 0.2.6(@swc/core@1.7.35(@swc/helpers@0.5.13))(webpack@5.95.0)
+        version: 0.2.6(@swc/core@1.7.35(@swc/helpers@0.5.13))(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4))
       typescript:
         specifier: ^5.6.2
         version: 5.6.2
@@ -2378,7 +2381,7 @@ importers:
         version: 4.3.2(vite@5.4.8(@types/node@22.7.4)(terser@5.31.1))
       html-webpack-plugin:
         specifier: ^5.6.0
-        version: 5.6.0(@rspack/core@1.0.10(@swc/helpers@0.5.13))(webpack@5.95.0)
+        version: 5.6.0(@rspack/core@1.0.10(@swc/helpers@0.5.13))(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4))
       react:
         specifier: ^18.3.1
         version: 18.3.1
@@ -2387,7 +2390,7 @@ importers:
         version: 18.3.1(react@18.3.1)
       swc-loader:
         specifier: ^0.2.6
-        version: 0.2.6(@swc/core@1.7.35(@swc/helpers@0.5.13))(webpack@5.95.0)
+        version: 0.2.6(@swc/core@1.7.35(@swc/helpers@0.5.13))(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4))
       typescript:
         specifier: ^5.6.2
         version: 5.6.2
@@ -12456,17 +12459,17 @@ snapshots:
       '@webassemblyjs/ast': 1.12.1
       '@xtuc/long': 4.2.2
 
-  '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.95.0)':
+  '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-dev-server@5.1.0)(webpack@5.95.0))(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4))':
     dependencies:
       webpack: 5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4)
       webpack-cli: 5.1.4(webpack-dev-server@5.1.0)(webpack@5.95.0)
 
-  '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.95.0)':
+  '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-dev-server@5.1.0)(webpack@5.95.0))(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4))':
     dependencies:
       webpack: 5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4)
       webpack-cli: 5.1.4(webpack-dev-server@5.1.0)(webpack@5.95.0)
 
-  '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.1.0)(webpack@5.95.0)':
+  '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-dev-server@5.1.0)(webpack@5.95.0))(webpack-dev-server@5.1.0(webpack-cli@5.1.4)(webpack@5.95.0))(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4))':
     dependencies:
       webpack: 5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4)
       webpack-cli: 5.1.4(webpack-dev-server@5.1.0)(webpack@5.95.0)
@@ -14412,7 +14415,7 @@ snapshots:
 
   html-void-elements@3.0.0: {}
 
-  html-webpack-plugin@5.6.0(@rspack/core@1.0.10(@swc/helpers@0.5.13))(webpack@5.95.0):
+  html-webpack-plugin@5.6.0(@rspack/core@1.0.10(@swc/helpers@0.5.13))(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4)):
     dependencies:
       '@types/html-minifier-terser': 6.1.0
       html-minifier-terser: 6.1.0
@@ -16560,7 +16563,7 @@ snapshots:
       csso: 5.0.5
       picocolors: 1.1.0
 
-  swc-loader@0.2.6(@swc/core@1.7.35(@swc/helpers@0.5.13))(webpack@5.95.0):
+  swc-loader@0.2.6(@swc/core@1.7.35(@swc/helpers@0.5.13))(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4)):
     dependencies:
       '@swc/core': 1.7.35(@swc/helpers@0.5.13)
       '@swc/counter': 0.1.3
@@ -16630,26 +16633,26 @@ snapshots:
       mkdirp: 1.0.4
       yallist: 4.0.0
 
-  terser-webpack-plugin@5.3.10(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)):
+  terser-webpack-plugin@5.3.10(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4)):
     dependencies:
       '@jridgewell/trace-mapping': 0.3.25
       jest-worker: 27.5.1
       schema-utils: 3.3.0
       serialize-javascript: 6.0.2
       terser: 5.31.1
-      webpack: 5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)
+      webpack: 5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4)
     optionalDependencies:
       '@swc/core': 1.7.35(@swc/helpers@0.5.13)
       esbuild: 0.23.1
 
-  terser-webpack-plugin@5.3.10(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack@5.95.0):
+  terser-webpack-plugin@5.3.10(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)):
     dependencies:
       '@jridgewell/trace-mapping': 0.3.25
       jest-worker: 27.5.1
       schema-utils: 3.3.0
       serialize-javascript: 6.0.2
       terser: 5.31.1
-      webpack: 5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4)
+      webpack: 5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)
     optionalDependencies:
       '@swc/core': 1.7.35(@swc/helpers@0.5.13)
       esbuild: 0.23.1
@@ -17293,9 +17296,9 @@ snapshots:
   webpack-cli@5.1.4(webpack-dev-server@5.1.0)(webpack@5.95.0):
     dependencies:
       '@discoveryjs/json-ext': 0.5.7
-      '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.95.0)
-      '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.95.0)
-      '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.1.0)(webpack@5.95.0)
+      '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-dev-server@5.1.0)(webpack@5.95.0))(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4))
+      '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-dev-server@5.1.0)(webpack@5.95.0))(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4))
+      '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-dev-server@5.1.0)(webpack@5.95.0))(webpack-dev-server@5.1.0(webpack-cli@5.1.4)(webpack@5.95.0))(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4))
       colorette: 2.0.20
       commander: 10.0.1
       cross-spawn: 7.0.3
@@ -17309,7 +17312,7 @@ snapshots:
     optionalDependencies:
       webpack-dev-server: 5.1.0(webpack-cli@5.1.4)(webpack@5.95.0)
 
-  webpack-dev-middleware@7.4.2(webpack@5.95.0):
+  webpack-dev-middleware@7.4.2(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4)):
     dependencies:
       colorette: 2.0.20
       memfs: 4.9.3
@@ -17348,7 +17351,7 @@ snapshots:
       serve-index: 1.9.1
       sockjs: 0.3.24
       spdy: 4.0.2
-      webpack-dev-middleware: 7.4.2(webpack@5.95.0)
+      webpack-dev-middleware: 7.4.2(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4))
       ws: 8.18.0
     optionalDependencies:
       webpack: 5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4)
@@ -17421,7 +17424,7 @@ snapshots:
       neo-async: 2.6.2
       schema-utils: 3.3.0
       tapable: 2.2.1
-      terser-webpack-plugin: 5.3.10(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack@5.95.0)
+      terser-webpack-plugin: 5.3.10(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack@5.95.0(@swc/core@1.7.35(@swc/helpers@0.5.13))(esbuild@0.23.1)(webpack-cli@5.1.4))
       watchpack: 2.4.1
       webpack-sources: 3.2.3
     optionalDependencies:


Test patch:
diff --git a/e2e/react-router/basic-file-based/package.json b/e2e/react-router/basic-file-based/package.json
index 2cdf96845..9422d90bb 100644
--- a/e2e/react-router/basic-file-based/package.json
+++ b/e2e/react-router/basic-file-based/package.json
@@ -13,6 +13,7 @@
     "@tanstack/react-router": "workspace:^",
     "@tanstack/router-devtools": "workspace:^",
     "@tanstack/router-plugin": "workspace:^",
+    "@tanstack/router-zod-adapter": "workspace:^",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "redaxios": "^0.5.1",
diff --git a/e2e/react-router/basic-file-based/src/routeTree.gen.ts b/e2e/react-router/basic-file-based/src/routeTree.gen.ts
index 149df203a..095f3f661 100644
--- a/e2e/react-router/basic-file-based/src/routeTree.gen.ts
+++ b/e2e/react-router/basic-file-based/src/routeTree.gen.ts
@@ -8,6 +8,8 @@
 
 // This file is auto-generated by TanStack Router
 
+import { createFileRoute } from '@tanstack/react-router'
+
 // Import Routes
 
 import { Route as rootRoute } from './routes/__root'
@@ -17,11 +19,23 @@ import { Route as IndexImport } from './routes/index'
 import { Route as PostsIndexImport } from './routes/posts.index'
 import { Route as PostsPostIdImport } from './routes/posts.$postId'
 import { Route as LayoutLayout2Import } from './routes/_layout/_layout-2'
+import { Route as groupLazyinsideImport } from './routes/(group)/lazyinside'
+import { Route as groupLayoutImport } from './routes/(group)/_layout'
 import { Route as LayoutLayout2LayoutBImport } from './routes/_layout/_layout-2/layout-b'
 import { Route as LayoutLayout2LayoutAImport } from './routes/_layout/_layout-2/layout-a'
+import { Route as groupLayoutInsideImport } from './routes/(group)/_layout.inside'
+
+// Create Virtual Routes
+
+const groupImport = createFileRoute('/(group)')()
 
 // Create/Update Routes
 
+const groupRoute = groupImport.update({
+  id: '/(group)',
+  getParentRoute: () => rootRoute,
+} as any)
+
 const PostsRoute = PostsImport.update({
   path: '/posts',
   getParentRoute: () => rootRoute,
@@ -52,6 +66,18 @@ const LayoutLayout2Route = LayoutLayout2Import.update({
   getParentRoute: () => LayoutRoute,
 } as any)
 
+const groupLazyinsideRoute = groupLazyinsideImport
+  .update({
+    path: '/lazyinside',
+    getParentRoute: () => groupRoute,
+  } as any)
+  .lazy(() => import('./routes/(group)/lazyinside.lazy').then((d) => d.Route))
+
+const groupLayoutRoute = groupLayoutImport.update({
+  id: '/_layout',
+  getParentRoute: () => groupRoute,
+} as any)
+
 const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBImport.update({
   path: '/layout-b',
   getParentRoute: () => LayoutLayout2Route,
@@ -62,6 +88,11 @@ const LayoutLayout2LayoutARoute = LayoutLayout2LayoutAImport.update({
   getParentRoute: () => LayoutLayout2Route,
 } as any)
 
+const groupLayoutInsideRoute = groupLayoutInsideImport.update({
+  path: '/inside',
+  getParentRoute: () => groupLayoutRoute,
+} as any)
+
 // Populate the FileRoutesByPath interface
 
 declare module '@tanstack/react-router' {
@@ -87,6 +118,27 @@ declare module '@tanstack/react-router' {
       preLoaderRoute: typeof PostsImport
       parentRoute: typeof rootRoute
     }
+    '/(group)': {
+      id: '/(group)'
+      path: '/'
+      fullPath: '/'
+      preLoaderRoute: typeof groupImport
+      parentRoute: typeof rootRoute
+    }
+    '/(group)/_layout': {
+      id: '/(group)/_layout'
+      path: '/'
+      fullPath: '/'
+      preLoaderRoute: typeof groupLayoutImport
+      parentRoute: typeof groupRoute
+    }
+    '/(group)/lazyinside': {
+      id: '/(group)/lazyinside'
+      path: '/lazyinside'
+      fullPath: '/lazyinside'
+      preLoaderRoute: typeof groupLazyinsideImport
+      parentRoute: typeof groupImport
+    }
     '/_layout/_layout-2': {
       id: '/_layout/_layout-2'
       path: ''
@@ -108,6 +160,13 @@ declare module '@tanstack/react-router' {
       preLoaderRoute: typeof PostsIndexImport
       parentRoute: typeof PostsImport
     }
+    '/(group)/_layout/inside': {
+      id: '/(group)/_layout/inside'
+      path: '/inside'
+      fullPath: '/inside'
+      preLoaderRoute: typeof groupLayoutInsideImport
+      parentRoute: typeof groupLayoutImport
+    }
     '/_layout/_layout-2/layout-a': {
       id: '/_layout/_layout-2/layout-a'
       path: '/layout-a'
@@ -164,21 +223,49 @@ const PostsRouteChildren: PostsRouteChildren = {
 
 const PostsRouteWithChildren = PostsRoute._addFileChildren(PostsRouteChildren)
 
+interface groupLayoutRouteChildren {
+  groupLayoutInsideRoute: typeof groupLayoutInsideRoute
+}
+
+const groupLayoutRouteChildren: groupLayoutRouteChildren = {
+  groupLayoutInsideRoute: groupLayoutInsideRoute,
+}
+
+const groupLayoutRouteWithChildren = groupLayoutRoute._addFileChildren(
+  groupLayoutRouteChildren,
+)
+
+interface groupRouteChildren {
+  groupLayoutRoute: typeof groupLayoutRouteWithChildren
+  groupLazyinsideRoute: typeof groupLazyinsideRoute
+}
+
+const groupRouteChildren: groupRouteChildren = {
+  groupLayoutRoute: groupLayoutRouteWithChildren,
+  groupLazyinsideRoute: groupLazyinsideRoute,
+}
+
+const groupRouteWithChildren = groupRoute._addFileChildren(groupRouteChildren)
+
 export interface FileRoutesByFullPath {
-  '/': typeof IndexRoute
+  '/': typeof groupLayoutRouteWithChildren
   '': typeof LayoutLayout2RouteWithChildren
   '/posts': typeof PostsRouteWithChildren
+  '/lazyinside': typeof groupLazyinsideRoute
   '/posts/$postId': typeof PostsPostIdRoute
   '/posts/': typeof PostsIndexRoute
+  '/inside': typeof groupLayoutInsideRoute
   '/layout-a': typeof LayoutLayout2LayoutARoute
   '/layout-b': typeof LayoutLayout2LayoutBRoute
 }
 
 export interface FileRoutesByTo {
-  '/': typeof IndexRoute
+  '/': typeof groupLayoutRouteWithChildren
   '': typeof LayoutLayout2RouteWithChildren
+  '/lazyinside': typeof groupLazyinsideRoute
   '/posts/$postId': typeof PostsPostIdRoute
   '/posts': typeof PostsIndexRoute
+  '/inside': typeof groupLayoutInsideRoute
   '/layout-a': typeof LayoutLayout2LayoutARoute
   '/layout-b': typeof LayoutLayout2LayoutBRoute
 }
@@ -188,9 +275,13 @@ export interface FileRoutesById {
   '/': typeof IndexRoute
   '/_layout': typeof LayoutRouteWithChildren
   '/posts': typeof PostsRouteWithChildren
+  '/(group)': typeof groupRouteWithChildren
+  '/(group)/_layout': typeof groupLayoutRouteWithChildren
+  '/(group)/lazyinside': typeof groupLazyinsideRoute
   '/_layout/_layout-2': typeof LayoutLayout2RouteWithChildren
   '/posts/$postId': typeof PostsPostIdRoute
   '/posts/': typeof PostsIndexRoute
+  '/(group)/_layout/inside': typeof groupLayoutInsideRoute
   '/_layout/_layout-2/layout-a': typeof LayoutLayout2LayoutARoute
   '/_layout/_layout-2/layout-b': typeof LayoutLayout2LayoutBRoute
 }
@@ -201,20 +292,34 @@ export interface FileRouteTypes {
     | '/'
     | ''
     | '/posts'
+    | '/lazyinside'
     | '/posts/$postId'
     | '/posts/'
+    | '/inside'
     | '/layout-a'
     | '/layout-b'
   fileRoutesByTo: FileRoutesByTo
-  to: '/' | '' | '/posts/$postId' | '/posts' | '/layout-a' | '/layout-b'
+  to:
+    | '/'
+    | ''
+    | '/lazyinside'
+    | '/posts/$postId'
+    | '/posts'
+    | '/inside'
+    | '/layout-a'
+    | '/layout-b'
   id:
     | '__root__'
     | '/'
     | '/_layout'
     | '/posts'
+    | '/(group)'
+    | '/(group)/_layout'
+    | '/(group)/lazyinside'
     | '/_layout/_layout-2'
     | '/posts/$postId'
     | '/posts/'
+    | '/(group)/_layout/inside'
     | '/_layout/_layout-2/layout-a'
     | '/_layout/_layout-2/layout-b'
   fileRoutesById: FileRoutesById
@@ -224,12 +329,14 @@ export interface RootRouteChildren {
   IndexRoute: typeof IndexRoute
   LayoutRoute: typeof LayoutRouteWithChildren
   PostsRoute: typeof PostsRouteWithChildren
+  groupRoute: typeof groupRouteWithChildren
 }
 
 const rootRouteChildren: RootRouteChildren = {
   IndexRoute: IndexRoute,
   LayoutRoute: LayoutRouteWithChildren,
   PostsRoute: PostsRouteWithChildren,
+  groupRoute: groupRouteWithChildren,
 }
 
 export const routeTree = rootRoute
@@ -246,7 +353,8 @@ export const routeTree = rootRoute
       "children": [
         "/",
         "/_layout",
-        "/posts"
+        "/posts",
+        "/(group)"
       ]
     },
     "/": {
@@ -265,6 +373,24 @@ export const routeTree = rootRoute
         "/posts/"
       ]
     },
+    "/(group)": {
+      "filePath": "(group)",
+      "children": [
+        "/(group)/_layout",
+        "/(group)/lazyinside"
+      ]
+    },
+    "/(group)/_layout": {
+      "filePath": "(group)/_layout.tsx",
+      "parent": "/(group)",
+      "children": [
+        "/(group)/_layout/inside"
+      ]
+    },
+    "/(group)/lazyinside": {
+      "filePath": "(group)/lazyinside.tsx",
+      "parent": "/(group)"
+    },
     "/_layout/_layout-2": {
       "filePath": "_layout/_layout-2.tsx",
       "parent": "/_layout",
@@ -281,6 +407,10 @@ export const routeTree = rootRoute
       "filePath": "posts.index.tsx",
       "parent": "/posts"
     },
+    "/(group)/_layout/inside": {
+      "filePath": "(group)/_layout.inside.tsx",
+      "parent": "/(group)/_layout"
+    },
     "/_layout/_layout-2/layout-a": {
       "filePath": "_layout/_layout-2/layout-a.tsx",
       "parent": "/_layout/_layout-2"
diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/_layout.inside.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/_layout.inside.tsx
new file mode 100644
index 000000000..d8984fc63
--- /dev/null
+++ b/e2e/react-router/basic-file-based/src/routes/(group)/_layout.inside.tsx
@@ -0,0 +1,21 @@
+import { createFileRoute, useSearch } from '@tanstack/react-router'
+import { z } from 'zod'
+import { zodSearchValidator } from '@tanstack/router-zod-adapter'
+
+export const Route = createFileRoute('/(group)/_layout/inside')({
+  validateSearch: zodSearchValidator(
+    z.object({ hello: z.string().optional() }),
+  ),
+  component: () => {
+    const searchViaHook = useSearch({ from: '/(group)/_layout/inside' })
+    const searchViaRouteHook = Route.useSearch()
+    return (
+      <>
+        <div data-testid="search-via-hook">{searchViaHook.hello}</div>
+        <div data-testid="search-via-route-hook">
+          {searchViaRouteHook.hello}
+        </div>
+      </>
+    )
+  },
+})
diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/_layout.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/_layout.tsx
new file mode 100644
index 000000000..4b755791c
--- /dev/null
+++ b/e2e/react-router/basic-file-based/src/routes/(group)/_layout.tsx
@@ -0,0 +1,10 @@
+import { Outlet, createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/(group)/_layout')({
+  component: () => (
+    <>
+      <div>/(group)/_layout!</div>
+      <Outlet />
+    </>
+  ),
+})
diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx
new file mode 100644
index 000000000..43240278f
--- /dev/null
+++ b/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx
@@ -0,0 +1,16 @@
+import { createLazyFileRoute, useSearch } from '@tanstack/react-router'
+
+export const Route = createLazyFileRoute('/(group)/lazyinside')({
+  component: () => {
+    const searchViaHook = useSearch({ from: '/(group)/lazyinside' })
+    const searchViaRouteHook = Route.useSearch()
+    return (
+      <>
+        <div data-testid="search-via-hook">{searchViaHook.hello}</div>
+        <div data-testid="search-via-route-hook">
+          {searchViaRouteHook.hello}
+        </div>
+      </>
+    )
+  },
+})
diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.tsx
new file mode 100644
index 000000000..d0803ef20
--- /dev/null
+++ b/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.tsx
@@ -0,0 +1,9 @@
+import { createFileRoute } from '@tanstack/react-router'
+import { z } from 'zod'
+import { zodSearchValidator } from '@tanstack/router-zod-adapter'
+
+export const Route = createFileRoute('/(group)/lazyinside')({
+  validateSearch: zodSearchValidator(
+    z.object({ hello: z.string().optional() }),
+  ),
+})
diff --git a/e2e/react-router/basic-file-based/src/routes/__root.tsx b/e2e/react-router/basic-file-based/src/routes/__root.tsx
index 6b57d1e23..2499f017b 100644
--- a/e2e/react-router/basic-file-based/src/routes/__root.tsx
+++ b/e2e/react-router/basic-file-based/src/routes/__root.tsx
@@ -43,6 +43,26 @@ function RootComponent() {
         >
           Layout
         </Link>{' '}
+        <Link
+          to="/inside"
+          data-testid="link-to-route-inside-group"
+          search={{ hello: 'world' }}
+          activeProps={{
+            className: 'font-bold',
+          }}
+        >
+          Inside Group
+        </Link>{' '}
+        <Link
+          to="/lazyinside"
+          data-testid="link-to-lazy-route-inside-group"
+          search={{ hello: 'world' }}
+          activeProps={{
+            className: 'font-bold',
+          }}
+        >
+          Lazy Inside Group
+        </Link>{' '}
         <Link
           // @ts-expect-error
           to="/this-route-does-not-exist"
diff --git a/e2e/react-router/basic-file-based/tests/app.spec.ts b/e2e/react-router/basic-file-based/tests/app.spec.ts
index f19a88b56..8d1e9110d 100644
--- a/e2e/react-router/basic-file-based/tests/app.spec.ts
+++ b/e2e/react-router/basic-file-based/tests/app.spec.ts
@@ -32,3 +32,15 @@ test('Navigating to a not-found route', async ({ page }) => {
   await page.getByRole('link', { name: 'Start Over' }).click()
   await expect(page.getByRole('heading')).toContainText('Welcome Home!')
 })
+
+test('Navigating to a route inside a route group', async ({ page }) => {
+  await page.getByTestId('link-to-route-inside-group').click()
+  await expect(page.getByTestId('search-via-hook')).toContainText('world')
+  await expect(page.getByTestId('search-via-route-hook')).toContainText('world')
+})
+
+test('Navigating to a lazy route inside a route group', async ({ page }) => {
+  await page.getByTestId('link-to-lazy-route-inside-group').click()
+  await expect(page.getByTestId('search-via-hook')).toContainText('world')
+  await expect(page.getByTestId('search-via-route-hook')).toContainText('world')
+})
diff --git a/e2e/react-router/basic-file-based/tsconfig.json b/e2e/react-router/basic-file-based/tsconfig.json
index c9e17e2b6..b50d8070e 100644
--- a/e2e/react-router/basic-file-based/tsconfig.json
+++ b/e2e/react-router/basic-file-based/tsconfig.json
@@ -2,6 +2,7 @@
   "compilerOptions": {
     "strict": true,
     "esModuleInterop": true,
-    "jsx": "react-jsx"
+    "jsx": "react-jsx",
+    "skipLibCheck": true
   }
 }
diff --git a/e2e/start/basic/app/routeTree.gen.ts b/e2e/start/basic/app/routeTree.gen.ts
index cebc80abe..41fd6a65f 100644
--- a/e2e/start/basic/app/routeTree.gen.ts
+++ b/e2e/start/basic/app/routeTree.gen.ts
@@ -12,6 +12,7 @@
 
 import { Route as rootRoute } from './routes/__root'
 import { Route as UsersImport } from './routes/users'
+import { Route as StatusImport } from './routes/status'
 import { Route as SearchParamsImport } from './routes/search-params'
 import { Route as RedirectImport } from './routes/redirect'
 import { Route as PostsImport } from './routes/posts'
@@ -34,6 +35,11 @@ const UsersRoute = UsersImport.update({
   getParentRoute: () => rootRoute,
 } as any)
 
+const StatusRoute = StatusImport.update({
+  path: '/status',
+  getParentRoute: () => rootRoute,
+} as any)
+
 const SearchParamsRoute = SearchParamsImport.update({
   path: '/search-params',
   getParentRoute: () => rootRoute,
@@ -150,6 +156,13 @@ declare module '@tanstack/react-router' {
       preLoaderRoute: typeof SearchParamsImport
       parentRoute: typeof rootRoute
     }
+    '/status': {
+      id: '/status'
+      path: '/status'
+      fullPath: '/status'
+      preLoaderRoute: typeof StatusImport
+      parentRoute: typeof rootRoute
+    }
     '/users': {
       id: '/users'
       path: '/users'
@@ -274,6 +287,7 @@ export interface FileRoutesByFullPath {
   '/posts': typeof PostsRouteWithChildren
   '/redirect': typeof RedirectRoute
   '/search-params': typeof SearchParamsRoute
+  '/status': typeof StatusRoute
   '/users': typeof UsersRouteWithChildren
   '/posts/$postId': typeof PostsPostIdRoute
   '/users/$userId': typeof UsersUserIdRoute
@@ -290,6 +304,7 @@ export interface FileRoutesByTo {
   '/deferred': typeof DeferredRoute
   '/redirect': typeof RedirectRoute
   '/search-params': typeof SearchParamsRoute
+  '/status': typeof StatusRoute
   '/posts/$postId': typeof PostsPostIdRoute
   '/users/$userId': typeof UsersUserIdRoute
   '/posts': typeof PostsIndexRoute
@@ -307,6 +322,7 @@ export interface FileRoutesById {
   '/posts': typeof PostsRouteWithChildren
   '/redirect': typeof RedirectRoute
   '/search-params': typeof SearchParamsRoute
+  '/status': typeof StatusRoute
   '/users': typeof UsersRouteWithChildren
   '/_layout/_layout-2': typeof LayoutLayout2RouteWithChildren
   '/posts/$postId': typeof PostsPostIdRoute
@@ -327,6 +343,7 @@ export interface FileRouteTypes {
     | '/posts'
     | '/redirect'
     | '/search-params'
+    | '/status'
     | '/users'
     | '/posts/$postId'
     | '/users/$userId'
@@ -342,6 +359,7 @@ export interface FileRouteTypes {
     | '/deferred'
     | '/redirect'
     | '/search-params'
+    | '/status'
     | '/posts/$postId'
     | '/users/$userId'
     | '/posts'
@@ -357,6 +375,7 @@ export interface FileRouteTypes {
     | '/posts'
     | '/redirect'
     | '/search-params'
+    | '/status'
     | '/users'
     | '/_layout/_layout-2'
     | '/posts/$postId'
@@ -376,6 +395,7 @@ export interface RootRouteChildren {
   PostsRoute: typeof PostsRouteWithChildren
   RedirectRoute: typeof RedirectRoute
   SearchParamsRoute: typeof SearchParamsRoute
+  StatusRoute: typeof StatusRoute
   UsersRoute: typeof UsersRouteWithChildren
   PostsPostIdDeepRoute: typeof PostsPostIdDeepRoute
 }
@@ -387,6 +407,7 @@ const rootRouteChildren: RootRouteChildren = {
   PostsRoute: PostsRouteWithChildren,
   RedirectRoute: RedirectRoute,
   SearchParamsRoute: SearchParamsRoute,
+  StatusRoute: StatusRoute,
   UsersRoute: UsersRouteWithChildren,
   PostsPostIdDeepRoute: PostsPostIdDeepRoute,
 }
@@ -409,6 +430,7 @@ export const routeTree = rootRoute
         "/posts",
         "/redirect",
         "/search-params",
+        "/status",
         "/users",
         "/posts/$postId/deep"
       ]
@@ -438,6 +460,9 @@ export const routeTree = rootRoute
     "/search-params": {
       "filePath": "search-params.tsx"
     },
+    "/status": {
+      "filePath": "status.tsx"
+    },
     "/users": {
       "filePath": "users.tsx",
       "children": [
diff --git a/e2e/start/basic/app/routes/status.tsx b/e2e/start/basic/app/routes/status.tsx
new file mode 100644
index 000000000..bd8ec12f3
--- /dev/null
+++ b/e2e/start/basic/app/routes/status.tsx
@@ -0,0 +1,30 @@
+import { createFileRoute } from '@tanstack/react-router'
+import { createServerFn, useServerFn } from '@tanstack/start'
+
+import { setResponseStatus } from 'vinxi/http'
+
+export const helloFn = createServerFn('GET', async () => {
+  setResponseStatus(225, `hello`)
+  return {
+    hello: 'world',
+  }
+})
+export const Route = createFileRoute('/status')({
+  component: StatusComponent,
+})
+
+function StatusComponent() {
+  const hello = useServerFn(helloFn)
+
+  return (
+    <div className="p-2">
+      <button
+        data-testid="invoke-server-fn"
+        className="px-4 py-2 bg-blue-500 text-white rounded-md"
+        onClick={() => hello()}
+      >
+        click me
+      </button>
+    </div>
+  )
+}
diff --git a/e2e/start/basic/tests/app.spec.ts b/e2e/start/basic/tests/app.spec.ts
index 225205b4b..8303f3cf5 100644
--- a/e2e/start/basic/tests/app.spec.ts
+++ b/e2e/start/basic/tests/app.spec.ts
@@ -78,3 +78,23 @@ test('Directly visiting the search-params route with search param set', async ({
   await expect(page.getByTestId('search-param')).toContainText('b')
   expect(page.url().endsWith('/search-params?step=b'))
 })
+
+test('invoking a server function with custom response status code', async ({
+  page,
+}) => {
+  await page.goto('/status')
+
+  await page.waitForLoadState('networkidle')
+  await page.getByTestId('invoke-server-fn').click()
+
+  const requestPromise = new Promise<void>((resolve) => {
+    page.on('response', async (response) => {
+      expect(response.status()).toBe(225)
+      expect(response.statusText()).toBe('hello')
+      expect(response.headers()['content-type']).toBe('application/json')
+      expect(await response.json()).toEqual({ hello: 'world' })
+      resolve()
+    })
+  })
+  await requestPromise
+})
diff --git a/packages/eslint-plugin-router/src/__tests__/create-route-property-order.rule.test.ts b/packages/eslint-plugin-router/src/__tests__/create-route-property-order.rule.test.ts
index 51a0743f4..227530ad2 100644
--- a/packages/eslint-plugin-router/src/__tests__/create-route-property-order.rule.test.ts
+++ b/packages/eslint-plugin-router/src/__tests__/create-route-property-order.rule.test.ts
@@ -21,10 +21,10 @@ const ruleTester = new RuleTester()
 
 // reduce the number of test cases by only testing a subset of the checked properties
 const testedCheckedProperties = [
-  checkedProperties[0],
-  checkedProperties[1],
-  checkedProperties[2],
-  checkedProperties[3],
+  checkedProperties[0]!,
+  checkedProperties[1]!,
+  checkedProperties[2]!,
+  checkedProperties[3]!,
 ]
 type TestedCheckedProperties = (typeof testedCheckedProperties)[number]
 const orderIndependentProps = ['gcTime', '...foo'] as const
@@ -165,6 +165,19 @@ const validTestCases = validTestMatrix.map(
   }),
 )
 
+invalidTestMatrix.push({
+  createRouteFunction: 'createFileRoute',
+  properties: {
+    invalid: ['loader', 'loaderDeps'],
+    valid: ['loaderDeps', 'loader'],
+  },
+})
+
+invalidTestMatrix.push({
+  createRouteFunction: 'createFileRoute',
+  properties: { invalid: ['meta', 'loader'], valid: ['loader', 'meta'] },
+})
+
 const invalidTestCases = invalidTestMatrix.map(
   ({ createRouteFunction, properties }) => ({
     name: `incorrect property order is detected for ${createRouteFunction} with order: ${properties.invalid.join(', ')}`,
diff --git a/packages/eslint-plugin-router/src/__tests__/create-route-property-order.utils.test.ts b/packages/eslint-plugin-router/src/__tests__/create-route-property-order.utils.test.ts
index b9edd6420..4dfb782e6 100644
--- a/packages/eslint-plugin-router/src/__tests__/create-route-property-order.utils.test.ts
+++ b/packages/eslint-plugin-router/src/__tests__/create-route-property-order.utils.test.ts
@@ -1,5 +1,8 @@
 import { describe, expect, test } from 'vitest'
-import { sortDataByOrder } from '../rules/create-route-property-order/create-route-property-order.utils'
+import {
+  getCheckedProperties,
+  sortDataByOrder,
+} from '../rules/create-route-property-order/create-route-property-order.utils'
 
 describe('create-route-property-order utils', () => {
   describe('sortDataByOrder', () => {
@@ -67,6 +70,63 @@ describe('create-route-property-order utils', () => {
         key: 'key',
         expected: [{ key: 'd' }, { key: 'a' }, { key: 'b' }, { key: 'c' }],
       },
+      {
+        data: [{ key: 'd' }, { key: 'b' }, { key: 'a' }, { key: 'c' }],
+        orderArray: [
+          [['a', 'b'], ['d']],
+          [['d'], ['c']],
+        ],
+        key: 'key',
+        expected: [{ key: 'b' }, { key: 'a' }, { key: 'd' }, { key: 'c' }],
+      },
+      {
+        data: [
+          { key: 'd' },
+          { key: 'b' },
+          { key: 'a' },
+          { key: 'c' },
+          { key: 'f' },
+        ],
+        orderArray: [
+          [
+            ['a', 'b'],
+            ['d', 'f'],
+          ],
+          [['d'], ['c']],
+        ],
+        key: 'key',
+        expected: [
+          { key: 'b' },
+          { key: 'a' },
+          { key: 'd' },
+          { key: 'f' },
+          { key: 'c' },
+        ],
+      },
+      {
+        data: [
+          { key: 'd' },
+          { key: 'b' },
+          { key: 'a' },
+          { key: 'c' },
+          { key: 'f' },
+        ],
+        orderArray: [
+          [
+            ['a', 'b'],
+            ['d', 'f'],
+          ],
+          [['d', 'f'], ['c']],
+        ],
+        key: 'key',
+        expected: [
+          { key: 'b' },
+          { key: 'a' },
+          { key: 'd' },
+          { key: 'f' },
+          { key: 'c' },
+        ],
+      },
     ] as const
     test.each(testCases)(
       '$data $orderArray $key $expected',
@@ -77,3 +137,43 @@ describe('create-route-property-order utils', () => {
     )
   })
 })
+
+describe('getCheckedProperties', () => {
+  const testCases = [
+    {
+      orderRules: [
+        [['a', 'b'], ['c']],
+        [['c'], ['d']],
+      ],
+      expected: ['a', 'b', 'c', 'd'],
+    },
+    {
+      orderRules: [
+        [['a', 'b'], ['c']],
+        [['d'], ['e']],
+      ],
+      expected: ['a', 'b', 'c', 'd', 'e'],
+    },
+    {
+      orderRules: [
+        [['a', 'b'], ['c']],
+        [['d'], ['e']],
+        [['c'], ['f']],
+      ],
+      expected: ['a', 'b', 'c', 'd', 'e', 'f'],
+    },
+    {
+      orderRules: [
+        [['a', 'b'], ['c']],
+        [['d'], ['e']],
+        [['c'], ['f']],
+        [['f'], ['g']],
+      ],
+      expected: ['a', 'b', 'c', 'd', 'e', 'f', 'g'],
+    },
+  ] as const
+  test.each(testCases)('$orderRules $expected', ({ orderRules, expected }) => {
+    const checkedProperties = getCheckedProperties(orderRules)
+    expect(checkedProperties).toEqual(expected)
+  })
+})
diff --git a/packages/react-router/tests/lazy/normal.tsx b/packages/react-router/tests/lazy/normal.tsx
new file mode 100644
index 000000000..1addf96c7
--- /dev/null
+++ b/packages/react-router/tests/lazy/normal.tsx
@@ -0,0 +1,13 @@
+import { createLazyFileRoute, createLazyRoute } from '../../src'
+
+export function Route(id: string) {
+  return createLazyRoute(id)({
+    component: () => <h1>I'm a normal route</h1>,
+  })
+}
+
+export function FileRoute(id: string) {
+  return createLazyFileRoute(id as any)({
+    component: () => <h1>I'm a normal file route</h1>,
+  })
+}
diff --git a/packages/react-router/tests/router.test.tsx b/packages/react-router/tests/router.test.tsx
index 5ec04873d..25e669663 100644
--- a/packages/react-router/tests/router.test.tsx
+++ b/packages/react-router/tests/router.test.tsx
@@ -7,6 +7,7 @@ import {
   screen,
   waitFor,
 } from '@testing-library/react'
+import { z } from 'zod'
 import {
   Link,
   Outlet,
@@ -16,7 +17,7 @@ import {
   createRoute,
   createRouter,
 } from '../src'
-import type { RouterHistory } from '../src'
+import type { AnyRoute, RouterOptions } from '../src'
 
 afterEach(() => {
   vi.resetAllMocks()
@@ -26,14 +27,19 @@ afterEach(() => {
 
 const mockFn1 = vi.fn()
 
-function createTestRouter(initialHistory?: RouterHistory) {
-  let history
-
-  if (initialHistory) {
-    history = initialHistory
-  }
-
-  const rootRoute = createRootRoute({})
+function createTestRouter(options?: RouterOptions<AnyRoute, 'never'>) {
+  const rootRoute = createRootRoute({
+    validateSearch: z.object({ root: z.string().optional() }),
+    component: () => {
+      const search = rootRoute.useSearch()
+      return (
+        <>
+          <div data-testid="search-root">{search.root ?? '$undefined'}</div>
+          <Outlet />
+        </>
+      )
+    },
+  })
   const indexRoute = createRoute({ getParentRoute: () => rootRoute, path: '/' })
   const postsRoute = createRoute({
     getParentRoute: () => rootRoute,
@@ -73,6 +79,67 @@ function createTestRouter(initialHistory?: RouterHistory) {
     getParentRoute: () => pathSegmentLayoutSplatRoute,
     path: '$',
   })
+  const protectedRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    id: '/_protected',
+  }).lazy(() => import('./lazy/normal').then((f) => f.Route('/_protected')))
+  const protectedLayoutRoute = createRoute({
+    getParentRoute: () => protectedRoute,
+    id: '/_layout',
+  }).lazy(() =>
+    import('./lazy/normal').then((f) => f.Route('/_protected/_layout')),
+  )
+  const protectedFileBasedLayoutRoute = createRoute({
+    getParentRoute: () => protectedRoute,
+    id: '/_fileBasedLayout',
+  }).lazy(() =>
+    import('./lazy/normal').then((f) =>
+      f.FileRoute('/_protected/_fileBasedLayout'),
+    ),
+  )
+  const protectedFileBasedLayoutParentRoute = createRoute({
+    getParentRoute: () => protectedFileBasedLayoutRoute,
+    path: '/fileBasedParent',
+  }).lazy(() =>
+    import('./lazy/normal').then((f) =>
+      f.FileRoute('/_protected/_fileBasedLayout/fileBasedParent'),
+    ),
+  )
+  const protectedLayoutParentRoute = createRoute({
+    getParentRoute: () => protectedLayoutRoute,
+    path: '/parent',
+  }).lazy(() =>
+    import('./lazy/normal').then((f) => f.Route('/_protected/_layout/parent')),
+  )
+  const protectedLayoutParentChildRoute = createRoute({
+    getParentRoute: () => protectedLayoutParentRoute,
+    path: '/child',
+  }).lazy(() =>
+    import('./lazy/normal').then((f) =>
+      f.Route('/_protected/_layout/parent/child'),
+    ),
+  )
+  const protectedFileBasedLayoutParentChildRoute = createRoute({
+    getParentRoute: () => protectedFileBasedLayoutParentRoute,
+    path: '/child',
+  }).lazy(() =>
+    import('./lazy/normal').then((f) =>
+      f.FileRoute('/_protected/_fileBasedLayout/fileBasedParent/child'),
+    ),
+  )
+  const searchRoute = createRoute({
+    validateSearch: z.object({ search: z.string().optional() }),
+    getParentRoute: () => rootRoute,
+    path: 'search',
+    component: () => {
+      const search = searchRoute.useSearch()
+      return (
+        <>
+          <div data-testid="search-search">{search.search ?? '$undefined'}</div>
+        </>
+      )
+    },
+  })
 
   const routeTree = rootRoute.addChildren([
     indexRoute,
@@ -85,9 +152,22 @@ function createTestRouter(initialHistory?: RouterHistory) {
       pathSegmentLayoutSplatIndexRoute,
       pathSegmentLayoutSplatSplatRoute,
     ]),
+    protectedRoute.addChildren([
+      protectedLayoutRoute.addChildren([
+        protectedLayoutParentRoute.addChildren([
+          protectedLayoutParentChildRoute,
+        ]),
+      ]),
+      protectedFileBasedLayoutRoute.addChildren([
+        protectedFileBasedLayoutParentRoute.addChildren([
+          protectedFileBasedLayoutParentChildRoute,
+        ]),
+      ]),
+    ]),
+    searchRoute,
   ])
 
-  const router = createRouter({ routeTree, history })
+  const router = createRouter({ routeTree, ...options })
 
   return {
     router,
@@ -104,9 +184,9 @@ function createTestRouter(initialHistory?: RouterHistory) {
 
 describe('encoding: URL param segment for /posts/$slug', () => {
   it('state.location.pathname, should have the params.slug value of "tanner"', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/posts/tanner'] }),
-    )
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/posts/tanner'] }),
+    })
 
     await act(() => router.load())
 
@@ -114,9 +194,9 @@ describe('encoding: URL param segment for /posts/$slug', () => {
   })
 
   it('state.location.pathname, should have the params.slug value of "🚀"', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/posts/🚀'] }),
-    )
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/posts/🚀'] }),
+    })
 
     await act(() => router.load())
 
@@ -124,9 +204,9 @@ describe('encoding: URL param segment for /posts/$slug', () => {
   })
 
   it('state.location.pathname, should have the params.slug value of "%F0%9F%9A%80"', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/posts/%F0%9F%9A%80'] }),
-    )
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/posts/%F0%9F%9A%80'] }),
+    })
 
     await act(() => router.load())
 
@@ -134,13 +214,13 @@ describe('encoding: URL param segment for /posts/$slug', () => {
   })
 
   it('state.location.pathname, should have the params.slug value of "framework%2Freact%2Fguide%2Ffile-based-routing%20tanstack"', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({
+    const { router } = createTestRouter({
+      history: createMemoryHistory({
         initialEntries: [
           '/posts/framework%2Freact%2Fguide%2Ffile-based-routing%20tanstack',
         ],
       }),
-    )
+    })
 
     await act(() => router.load())
 
@@ -150,9 +230,9 @@ describe('encoding: URL param segment for /posts/$slug', () => {
   })
 
   it('params.slug for the matched route, should be "tanner"', async () => {
-    const { router, routes } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/posts/tanner'] }),
-    )
+    const { router, routes } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/posts/tanner'] }),
+    })
 
     await act(() => router.load())
 
@@ -168,9 +248,9 @@ describe('encoding: URL param segment for /posts/$slug', () => {
   })
 
   it('params.slug for the matched route, should be "🚀"', async () => {
-    const { router, routes } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/posts/🚀'] }),
-    )
+    const { router, routes } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/posts/🚀'] }),
+    })
 
     await act(() => router.load())
 
@@ -186,9 +266,9 @@ describe('encoding: URL param segment for /posts/$slug', () => {
   })
 
   it('params.slug for the matched route, should be "🚀" instead of it being "%F0%9F%9A%80"', async () => {
-    const { router, routes } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/posts/%F0%9F%9A%80'] }),
-    )
+    const { router, routes } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/posts/%F0%9F%9A%80'] }),
+    })
 
     await act(() => router.load())
 
@@ -204,13 +284,13 @@ describe('encoding: URL param segment for /posts/$slug', () => {
   })
 
   it('params.slug for the matched route, should be "framework/react/guide/file-based-routing tanstack" instead of it being "framework%2Freact%2Fguide%2Ffile-based-routing%20tanstack"', async () => {
-    const { router, routes } = createTestRouter(
-      createMemoryHistory({
+    const { router, routes } = createTestRouter({
+      history: createMemoryHistory({
         initialEntries: [
           '/posts/framework%2Freact%2Fguide%2Ffile-based-routing%20tanstack',
         ],
       }),
-    )
+    })
 
     await act(() => router.load())
 
@@ -230,9 +310,9 @@ describe('encoding: URL param segment for /posts/$slug', () => {
 
 describe('encoding: URL splat segment for /$', () => {
   it('state.location.pathname, should have the params._splat value of "tanner"', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/tanner'] }),
-    )
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/tanner'] }),
+    })
 
     await router.load()
 
@@ -240,9 +320,9 @@ describe('encoding: URL splat segment for /$', () => {
   })
 
   it('state.location.pathname, should have the params._splat value of "🚀"', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/🚀'] }),
-    )
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/🚀'] }),
+    })
 
     await router.load()
 
@@ -250,9 +330,9 @@ describe('encoding: URL splat segment for /$', () => {
   })
 
   it('state.location.pathname, should have the params._splat value of "%F0%9F%9A%80"', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/%F0%9F%9A%80'] }),
-    )
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/%F0%9F%9A%80'] }),
+    })
 
     await router.load()
 
@@ -260,13 +340,13 @@ describe('encoding: URL splat segment for /$', () => {
   })
 
   it('state.location.pathname, should have the params._splat value of "framework%2Freact%2Fguide%2Ffile-based-routing%20tanstack"', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({
+    const { router } = createTestRouter({
+      history: createMemoryHistory({
         initialEntries: [
           '/framework%2Freact%2Fguide%2Ffile-based-routing%20tanstack',
         ],
       }),
-    )
+    })
 
     await router.load()
 
@@ -276,11 +356,11 @@ describe('encoding: URL splat segment for /$', () => {
   })
 
   it('state.location.pathname, should have the params._splat value of "framework/react/guide/file-based-routing tanstack"', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({
+    const { router } = createTestRouter({
+      history: createMemoryHistory({
         initialEntries: ['/framework/react/guide/file-based-routing tanstack'],
       }),
-    )
+    })
 
     await router.load()
 
@@ -290,9 +370,9 @@ describe('encoding: URL splat segment for /$', () => {
   })
 
   it('params._splat for the matched route, should be "tanner"', async () => {
-    const { router, routes } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/tanner'] }),
-    )
+    const { router, routes } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/tanner'] }),
+    })
 
     await router.load()
 
@@ -308,9 +388,9 @@ describe('encoding: URL splat segment for /$', () => {
   })
 
   it('params._splat for the matched route, should be "🚀"', async () => {
-    const { router, routes } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/🚀'] }),
-    )
+    const { router, routes } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/🚀'] }),
+    })
 
     await router.load()
 
@@ -326,9 +406,9 @@ describe('encoding: URL splat segment for /$', () => {
   })
 
   it('params._splat for the matched route, should be "🚀" instead of it being "%F0%9F%9A%80"', async () => {
-    const { router, routes } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/%F0%9F%9A%80'] }),
-    )
+    const { router, routes } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/%F0%9F%9A%80'] }),
+    })
 
     await router.load()
 
@@ -344,11 +424,11 @@ describe('encoding: URL splat segment for /$', () => {
   })
 
   it('params._splat for the matched route, should be "framework/react/guide/file-based-routing tanstack"', async () => {
-    const { router, routes } = createTestRouter(
-      createMemoryHistory({
+    const { router, routes } = createTestRouter({
+      history: createMemoryHistory({
         initialEntries: ['/framework/react/guide/file-based-routing tanstack'],
       }),
-    )
+    })
 
     await router.load()
 
@@ -401,9 +481,9 @@ describe('encoding: URL path segment', () => {
   ])(
     'should resolve $input to $output when the path segment is $type',
     async ({ input, output }) => {
-      const { router } = createTestRouter(
-        createMemoryHistory({ initialEntries: [input] }),
-      )
+      const { router } = createTestRouter({
+        history: createMemoryHistory({ initialEntries: [input] }),
+      })
 
       render(<RouterProvider router={router} />)
       await act(() => router.load())
@@ -415,9 +495,9 @@ describe('encoding: URL path segment', () => {
 
 describe('router emits events during rendering', () => {
   it('during initial load, should emit the "onResolved" event', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/'] }),
-    )
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/'] }),
+    })
 
     const unsub = router.subscribe('onResolved', mockFn1)
     await router.load()
@@ -428,9 +508,9 @@ describe('router emits events during rendering', () => {
   })
 
   it('after a navigation, should have emitted the "onResolved" event twice', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/'] }),
-    )
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/'] }),
+    })
 
     const unsub = router.subscribe('onResolved', mockFn1)
     await router.load()
@@ -527,9 +607,9 @@ describe('transformer functions are defined', () => {
 
 describe('router matches URLs to route definitions', () => {
   it('solo splat route matches index route', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/solo-splat'] }),
-    )
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/solo-splat'] }),
+    })
 
     await act(() => router.load())
 
@@ -540,9 +620,9 @@ describe('router matches URLs to route definitions', () => {
   })
 
   it('solo splat route matches with splat', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/solo-splat/test'] }),
-    )
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/solo-splat/test'] }),
+    })
 
     await act(() => router.load())
 
@@ -553,9 +633,9 @@ describe('router matches URLs to route definitions', () => {
   })
 
   it('layout splat route matches with splat', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/layout-splat/test'] }),
-    )
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/layout-splat/test'] }),
+    })
 
     await act(() => router.load())
 
@@ -567,9 +647,9 @@ describe('router matches URLs to route definitions', () => {
   })
 
   it('layout splat route matches without splat', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/layout-splat'] }),
-    )
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/layout-splat'] }),
+    })
 
     await act(() => router.load())
 
@@ -583,9 +663,107 @@ describe('router matches URLs to route definitions', () => {
 
 describe('invalidate', () => {
   it('after router.invalid(), routes should be `valid` again after loading', async () => {
-    const { router } = createTestRouter(
-      createMemoryHistory({ initialEntries: ['/'] }),
-    )
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/'] }),
+    })
+
+    await act(() => router.load())
+
+    router.state.matches.forEach((match) => {
+      expect(match.invalid).toBe(false)
+    })
+
+    await act(() => router.invalidate())
+
+    router.state.matches.forEach((match) => {
+      expect(match.invalid).toBe(false)
+    })
+  })
+})
+
+describe('search params in URL', () => {
+  const testCases = [
+    { route: '/', search: { root: 'world' } },
+    { route: '/', search: { root: 'world', unknown: 'asdf' } },
+    { route: '/search', search: { search: 'foo' } },
+    { route: '/search', search: { root: 'world', search: 'foo' } },
+    {
+      route: '/search',
+      search: { root: 'world', search: 'foo', unknown: 'asdf' },
+    },
+  ]
+  describe.each([undefined, false])(
+    'does not modify the search params in the URL when search.strict=%s',
+    (strict) => {
+      it.each(testCases)(
+        'at $route with search params $search',
+        async ({ route, search }) => {
+          const { router } = createTestRouter({ search: { strict } })
+          window.history.replaceState(
+            null,
+            '',
+            `${route}?${new URLSearchParams(search as Record<string, string>).toString()}`,
+          )
+
+          render(<RouterProvider router={router} />)
+          await act(() => router.load())
+
+          expect(await screen.findByTestId('search-root')).toHaveTextContent(
+            search.root ?? '$undefined',
+          )
+          if (route === '/search') {
+            expect(
+              await screen.findByTestId('search-search'),
+            ).toHaveTextContent(search.search ?? '$undefined')
+          }
+          expect(router.state.location.search).toEqual(search)
+          const parsedSearch = new URLSearchParams(window.location.search)
+          expect(parsedSearch.size).toBe(Object.keys(search).length)
+          for (const [key, value] of Object.entries(search)) {
+            expect(parsedSearch.get(key)).toBe(value)
+          }
+        },
+      )
+    },
+  )
+
+  describe('removes unknown search params in the URL when search.strict=true', () => {
+    it.each(testCases)('%j', async ({ route, search }) => {
+      const { router } = createTestRouter({ search: { strict: true } })
+      window.history.replaceState(
+        null,
+        '',
+        `${route}?${new URLSearchParams(search as Record<string, string>).toString()}`,
+      )
+      render(<RouterProvider router={router} />)
+      await act(() => router.load())
+      await expect(await screen.findByTestId('search-root')).toHaveTextContent(
+        search.root ?? 'undefined',
+      )
+      if (route === '/search') {
+        expect(await screen.findByTestId('search-search')).toHaveTextContent(
+          search.search ?? 'undefined',
+        )
+      }
+
+      expect(window.location.pathname).toEqual(route)
+      const expectedSearch = { ...search }
+      delete expectedSearch.unknown
+      expect(router.state.location.search).toEqual(expectedSearch)
+      const parsedSearch = new URLSearchParams(window.location.search)
+      expect(parsedSearch.size).toBe(Object.keys(expectedSearch).length)
+      for (const [key, value] of Object.entries(expectedSearch)) {
+        expect(parsedSearch.get(key)).toBe(value)
+      }
+    })
+  })
+})
+
+/*
+  it('updates search params in URL upon initial load according to the result of validateSearch', async () => {
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/'] }),
+    })
 
     await act(() => router.load())
 
@@ -605,4 +783,79 @@ describe('invalidate', () => {
       expect(match.invalid).toBe(false)
     })
   })
+})
+  */
+
+describe('route ids should be consistent after rebuilding the route tree', () => {
+  it('should have the same route ids after rebuilding the route tree', async () => {
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/'] }),
+    })
+
+    const originalRouteIds = Object.keys(router.routesById)
+
+    await act(() =>
+      router.navigate({
+        to: '/parent/child',
+      }),
+    )
+
+    await act(() =>
+      router.navigate({
+        to: '/filBasedParent/child',
+      }),
+    )
+
+    router.buildRouteTree()
+
+    const rebuiltRouteIds = Object.keys(router.routesById)
+
+    originalRouteIds.forEach((id) => {
+      expect(rebuiltRouteIds).toContain(id)
+    })
+
+    rebuiltRouteIds.forEach((id) => {
+      expect(originalRouteIds).toContain(id)
+    })
+  })
+})
+
+describe('route id uniqueness', () => {
+  it('flatRoute should not have routes with duplicated route ids', () => {
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/'] }),
+    })
+    const routeIdSet = new Set<string>()
+
+    router.flatRoutes.forEach((route) => {
+      expect(routeIdSet.has(route.id)).toBe(false)
+      routeIdSet.add(route.id)
+    })
+  })
+
+  it('routesById should not have routes duplicated route ids', () => {
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/'] }),
+    })
+
+    const routeIdSet = new Set<string>()
+
+    Object.values(router.routesById).forEach((route) => {
+      expect(routeIdSet.has(route.id)).toBe(false)
+      routeIdSet.add(route.id)
+    })
+  })
+
+  it('routesByPath should not have routes duplicated route ids', () => {
+    const { router } = createTestRouter({
+      history: createMemoryHistory({ initialEntries: ['/'] }),
+    })
+
+    const routeIdSet = new Set<string>()
+
+    Object.values(router.routesByPath).forEach((route) => {
+      expect(routeIdSet.has(route.id)).toBe(false)
+      routeIdSet.add(route.id)
+    })
+  })
 })
diff --git a/packages/react-router/tests/useNavigate.test.tsx b/packages/react-router/tests/useNavigate.test.tsx
index c00b108ea..06d8c196f 100644
--- a/packages/react-router/tests/useNavigate.test.tsx
+++ b/packages/react-router/tests/useNavigate.test.tsx
@@ -1238,9 +1238,12 @@ test('when setting search params with 2 parallel navigate calls', async () => {
 
   const IndexComponent = () => {
     const navigate = useNavigate()
+    const search = indexRoute.useSearch()
     return (
       <React.Fragment>
         <h1>Index</h1>
+        <div data-testid="param1">{search.param1}</div>
+        <div data-testid="param2">{search.param2}</div>
         <button
           onClick={() => {
             navigate({
@@ -1284,5 +1287,10 @@ test('when setting search params with 2 parallel navigate calls', async () => {
 
   fireEvent.click(postsButton)
 
+  expect(await screen.findByTestId('param1')).toHaveTextContent('foo')
+  expect(await screen.findByTestId('param2')).toHaveTextContent('bar')
   expect(router.state.location.search).toEqual({ param1: 'foo', param2: 'bar' })
+  const search = new URLSearchParams(window.location.search)
+  expect(search.get('param1')).toEqual('foo')
+  expect(search.get('param2')).toEqual('bar')
 })
diff --git a/packages/router-generator/tests/generator/file-modification/routeTree.snapshot.ts b/packages/router-generator/tests/generator/file-modification/routeTree.snapshot.ts
index 9e8e4be5c..6df9c95e8 100644
--- a/packages/router-generator/tests/generator/file-modification/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/file-modification/routeTree.snapshot.ts
@@ -54,28 +54,28 @@ const testFooRoute = testFooImport.update({
 declare module '@tanstack/react-router' {
   interface FileRoutesByPath {
     '/(test)/foo': {
-      id: '/foo'
+      id: '/(test)/foo'
       path: '/foo'
       fullPath: '/foo'
       preLoaderRoute: typeof testFooImport
       parentRoute: typeof rootRoute
     }
     '/(test)/initiallyEmpty': {
-      id: '/initiallyEmpty'
+      id: '/(test)/initiallyEmpty'
       path: '/initiallyEmpty'
       fullPath: '/initiallyEmpty'
       preLoaderRoute: typeof testInitiallyEmptyImport
       parentRoute: typeof rootRoute
     }
     '/(test)/initiallyLazy': {
-      id: '/initiallyLazy'
+      id: '/(test)/initiallyLazy'
       path: '/initiallyLazy'
       fullPath: '/initiallyLazy'
       preLoaderRoute: typeof testInitiallyLazyImport
       parentRoute: typeof rootRoute
     }
     '/(test)/bar': {
-      id: '/bar'
+      id: '/(test)/bar'
       path: '/bar'
       fullPath: '/bar'
       preLoaderRoute: typeof testBarLazyImport
@@ -102,10 +102,10 @@ export interface FileRoutesByTo {
 
 export interface FileRoutesById {
   __root__: typeof rootRoute
-  '/foo': typeof testFooRoute
-  '/initiallyEmpty': typeof testInitiallyEmptyRoute
-  '/initiallyLazy': typeof testInitiallyLazyRoute
-  '/bar': typeof testBarLazyRoute
+  '/(test)/foo': typeof testFooRoute
+  '/(test)/initiallyEmpty': typeof testInitiallyEmptyRoute
+  '/(test)/initiallyLazy': typeof testInitiallyLazyRoute
+  '/(test)/bar': typeof testBarLazyRoute
 }
 
 export interface FileRouteTypes {
@@ -113,7 +113,12 @@ export interface FileRouteTypes {
   fullPaths: '/foo' | '/initiallyEmpty' | '/initiallyLazy' | '/bar'
   fileRoutesByTo: FileRoutesByTo
   to: '/foo' | '/initiallyEmpty' | '/initiallyLazy' | '/bar'
-  id: '__root__' | '/foo' | '/initiallyEmpty' | '/initiallyLazy' | '/bar'
+  id:
+    | '__root__'
+    | '/(test)/foo'
+    | '/(test)/initiallyEmpty'
+    | '/(test)/initiallyLazy'
+    | '/(test)/bar'
   fileRoutesById: FileRoutesById
 }
 
@@ -143,22 +148,22 @@ export const routeTree = rootRoute
     "__root__": {
       "filePath": "__root.tsx",
       "children": [
-        "/foo",
-        "/initiallyEmpty",
-        "/initiallyLazy",
-        "/bar"
+        "/(test)/foo",
+        "/(test)/initiallyEmpty",
+        "/(test)/initiallyLazy",
+        "/(test)/bar"
       ]
     },
-    "/foo": {
+    "/(test)/foo": {
       "filePath": "(test)/foo.tsx"
     },
-    "/initiallyEmpty": {
+    "/(test)/initiallyEmpty": {
       "filePath": "(test)/initiallyEmpty.tsx"
     },
-    "/initiallyLazy": {
+    "/(test)/initiallyLazy": {
       "filePath": "(test)/initiallyLazy.tsx"
     },
-    "/bar": {
+    "/(test)/bar": {
       "filePath": "(test)/bar.lazy.tsx"
     }
   }
diff --git a/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts b/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts
index a41c906e0..c4dc705bb 100644
--- a/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts
@@ -216,7 +216,7 @@ declare module '@tanstack/react-router' {
       parentRoute: typeof FooRoute
     }
     '/(folder)/in-folder': {
-      id: '/in-folder'
+      id: '/(folder)/in-folder'
       path: '/in-folder'
       fullPath: '/in-folder'
       preLoaderRoute: typeof folderInFolderImport
@@ -552,7 +552,7 @@ export interface FileRoutesById {
   '/_layout-a2': typeof LayoutA2RouteWithChildren
   '/foo': typeof FooRouteWithChildren
   '/foo/_layout-b5': typeof FooLayoutB5RouteRouteWithChildren
-  '/in-folder': typeof folderInFolderRoute
+  '/(folder)/in-folder': typeof folderInFolderRoute
   '/_layout-a1/foo': typeof LayoutA1FooRoute
   '/_layout-a2/bar': typeof LayoutA2BarRoute
   '/foo/bar': typeof FooBarRoute
@@ -615,7 +615,7 @@ export interface FileRouteTypes {
     | '/_layout-a2'
     | '/foo'
     | '/foo/_layout-b5'
-    | '/in-folder'
+    | '/(folder)/in-folder'
     | '/_layout-a1/foo'
     | '/_layout-a2/bar'
     | '/foo/bar'
@@ -674,7 +674,7 @@ export const routeTree = rootRoute
         "/_layout-a1",
         "/_layout-a2",
         "/foo",
-        "/in-folder",
+        "/(folder)/in-folder",
         "/nested"
       ]
     },
@@ -715,7 +715,7 @@ export const routeTree = rootRoute
         "/foo/_layout-b5/"
       ]
     },
-    "/in-folder": {
+    "/(folder)/in-folder": {
       "filePath": "(folder)/in-folder.tsx"
     },
     "/_layout-a1/foo": {
diff --git a/packages/router-generator/tests/generator/route-groups/_layout.tsx b/packages/router-generator/tests/generator/route-groups/_layout.tsx
new file mode 100644
index 000000000..4654553db
--- /dev/null
+++ b/packages/router-generator/tests/generator/route-groups/_layout.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/(foo)/asdf/(bar)/_layout')({
+  component: () => <div>Hello /(foo)/asdf/(bar)/_layout!</div>,
+})
diff --git a/packages/router-generator/tests/generator/route-groups/routeTree.snapshot.ts b/packages/router-generator/tests/generator/route-groups/routeTree.snapshot.ts
index 06d86ac02..f3e568e93 100644
--- a/packages/router-generator/tests/generator/route-groups/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/route-groups/routeTree.snapshot.ts
@@ -8,62 +8,278 @@
 
 // This file is auto-generated by TanStack Router
 
+import { createFileRoute } from '@tanstack/react-router'
+
 // Import Routes
 
 import { Route as rootRoute } from './routes/__root'
+import { Route as fooAsdfLayoutImport } from './routes/(foo)/asdf/_layout'
+import { Route as fooAsdfLayoutFooImport } from './routes/(foo)/asdf/_layout.foo'
 import { Route as fooAsdfbarIdImport } from './routes/(foo)/asdf/(bar)/$id'
+import { Route as fooAsdfanotherGroupLayoutImport } from './routes/(foo)/asdf/(another-group)/_layout'
+import { Route as fooAsdfbarLayoutAboutImport } from './routes/(foo)/asdf/(bar)/_layout.about'
+import { Route as fooAsdfanotherGroupLayoutBazImport } from './routes/(foo)/asdf/(another-group)/_layout.baz'
+
+// Create Virtual Routes
+
+const fooAsdfImport = createFileRoute('/(foo)/asdf')()
+const fooAsdfanotherGroupImport = createFileRoute(
+  '/(foo)/asdf/(another-group)',
+)()
+const fooAsdfbarLayoutXyzLazyImport = createFileRoute(
+  '/(foo)/asdf/(bar)/_layout/xyz',
+)()
 
 // Create/Update Routes
 
-const fooAsdfbarIdRoute = fooAsdfbarIdImport.update({
-  path: '/asdf/$id',
+const fooAsdfRoute = fooAsdfImport.update({
+  path: '/asdf',
   getParentRoute: () => rootRoute,
 } as any)
 
+const fooAsdfanotherGroupRoute = fooAsdfanotherGroupImport.update({
+  id: '/(another-group)',
+  getParentRoute: () => fooAsdfRoute,
+} as any)
+
+const fooAsdfLayoutRoute = fooAsdfLayoutImport.update({
+  id: '/_layout',
+  getParentRoute: () => fooAsdfRoute,
+} as any)
+
+const fooAsdfLayoutFooRoute = fooAsdfLayoutFooImport.update({
+  path: '/foo',
+  getParentRoute: () => fooAsdfLayoutRoute,
+} as any)
+
+const fooAsdfbarIdRoute = fooAsdfbarIdImport.update({
+  path: '/$id',
+  getParentRoute: () => fooAsdfRoute,
+} as any)
+
+const fooAsdfanotherGroupLayoutRoute = fooAsdfanotherGroupLayoutImport.update({
+  id: '/_layout',
+  getParentRoute: () => fooAsdfanotherGroupRoute,
+} as any)
+
+const fooAsdfbarLayoutXyzLazyRoute = fooAsdfbarLayoutXyzLazyImport
+  .update({
+    path: '/xyz',
+    getParentRoute: () => fooAsdfRoute,
+  } as any)
+  .lazy(() =>
+    import('./routes/(foo)/asdf/(bar)/_layout.xyz.lazy').then((d) => d.Route),
+  )
+
+const fooAsdfbarLayoutAboutRoute = fooAsdfbarLayoutAboutImport.update({
+  path: '/about',
+  getParentRoute: () => fooAsdfRoute,
+} as any)
+
+const fooAsdfanotherGroupLayoutBazRoute =
+  fooAsdfanotherGroupLayoutBazImport.update({
+    path: '/baz',
+    getParentRoute: () => fooAsdfanotherGroupLayoutRoute,
+  } as any)
+
 // Populate the FileRoutesByPath interface
 
 declare module '@tanstack/react-router' {
   interface FileRoutesByPath {
+    '/(foo)/asdf': {
+      id: '/(foo)/asdf'
+      path: '/asdf'
+      fullPath: '/asdf'
+      preLoaderRoute: typeof fooAsdfImport
+      parentRoute: typeof rootRoute
+    }
+    '/(foo)/asdf/_layout': {
+      id: '/(foo)/asdf/_layout'
+      path: '/asdf'
+      fullPath: '/asdf'
+      preLoaderRoute: typeof fooAsdfLayoutImport
+      parentRoute: typeof fooAsdfRoute
+    }
+    '/(foo)/asdf/(another-group)': {
+      id: '/(foo)/asdf/(another-group)'
+      path: '/'
+      fullPath: '/asdf/'
+      preLoaderRoute: typeof fooAsdfanotherGroupImport
+      parentRoute: typeof fooAsdfImport
+    }
+    '/(foo)/asdf/(another-group)/_layout': {
+      id: '/(foo)/asdf/(another-group)/_layout'
+      path: '/'
+      fullPath: '/asdf/'
+      preLoaderRoute: typeof fooAsdfanotherGroupLayoutImport
+      parentRoute: typeof fooAsdfanotherGroupRoute
+    }
     '/(foo)/asdf/(bar)/$id': {
-      id: '/asdf/$id'
-      path: '/asdf/$id'
+      id: '/(foo)/asdf/(bar)/$id'
+      path: '/$id'
       fullPath: '/asdf/$id'
       preLoaderRoute: typeof fooAsdfbarIdImport
-      parentRoute: typeof rootRoute
+      parentRoute: typeof fooAsdfImport
+    }
+    '/(foo)/asdf/_layout/foo': {
+      id: '/(foo)/asdf/_layout/foo'
+      path: '/foo'
+      fullPath: '/asdf/foo'
+      preLoaderRoute: typeof fooAsdfLayoutFooImport
+      parentRoute: typeof fooAsdfLayoutImport
+    }
+    '/(foo)/asdf/(another-group)/_layout/baz': {
+      id: '/(foo)/asdf/(another-group)/_layout/baz'
+      path: '/baz'
+      fullPath: '/asdf/baz'
+      preLoaderRoute: typeof fooAsdfanotherGroupLayoutBazImport
+      parentRoute: typeof fooAsdfanotherGroupLayoutImport
+    }
+    '/(foo)/asdf/(bar)/_layout/about': {
+      id: '/(foo)/asdf/(bar)/_layout/about'
+      path: '/about'
+      fullPath: '/asdf/about'
+      preLoaderRoute: typeof fooAsdfbarLayoutAboutImport
+      parentRoute: typeof fooAsdfImport
+    }
+    '/(foo)/asdf/(bar)/_layout/xyz': {
+      id: '/(foo)/asdf/(bar)/_layout/xyz'
+      path: '/xyz'
+      fullPath: '/asdf/xyz'
+      preLoaderRoute: typeof fooAsdfbarLayoutXyzLazyImport
+      parentRoute: typeof fooAsdfImport
     }
   }
 }
 
 // Create and export the route tree
 
+interface fooAsdfLayoutRouteChildren {
+  fooAsdfLayoutFooRoute: typeof fooAsdfLayoutFooRoute
+}
+
+const fooAsdfLayoutRouteChildren: fooAsdfLayoutRouteChildren = {
+  fooAsdfLayoutFooRoute: fooAsdfLayoutFooRoute,
+}
+
+const fooAsdfLayoutRouteWithChildren = fooAsdfLayoutRoute._addFileChildren(
+  fooAsdfLayoutRouteChildren,
+)
+
+interface fooAsdfanotherGroupLayoutRouteChildren {
+  fooAsdfanotherGroupLayoutBazRoute: typeof fooAsdfanotherGroupLayoutBazRoute
+}
+
+const fooAsdfanotherGroupLayoutRouteChildren: fooAsdfanotherGroupLayoutRouteChildren =
+  {
+    fooAsdfanotherGroupLayoutBazRoute: fooAsdfanotherGroupLayoutBazRoute,
+  }
+
+const fooAsdfanotherGroupLayoutRouteWithChildren =
+  fooAsdfanotherGroupLayoutRoute._addFileChildren(
+    fooAsdfanotherGroupLayoutRouteChildren,
+  )
+
+interface fooAsdfanotherGroupRouteChildren {
+  fooAsdfanotherGroupLayoutRoute: typeof fooAsdfanotherGroupLayoutRouteWithChildren
+}
+
+const fooAsdfanotherGroupRouteChildren: fooAsdfanotherGroupRouteChildren = {
+  fooAsdfanotherGroupLayoutRoute: fooAsdfanotherGroupLayoutRouteWithChildren,
+}
+
+const fooAsdfanotherGroupRouteWithChildren =
+  fooAsdfanotherGroupRoute._addFileChildren(fooAsdfanotherGroupRouteChildren)
+
+interface fooAsdfRouteChildren {
+  fooAsdfLayoutRoute: typeof fooAsdfLayoutRouteWithChildren
+  fooAsdfanotherGroupRoute: typeof fooAsdfanotherGroupRouteWithChildren
+  fooAsdfbarIdRoute: typeof fooAsdfbarIdRoute
+  fooAsdfbarLayoutAboutRoute: typeof fooAsdfbarLayoutAboutRoute
+  fooAsdfbarLayoutXyzLazyRoute: typeof fooAsdfbarLayoutXyzLazyRoute
+}
+
+const fooAsdfRouteChildren: fooAsdfRouteChildren = {
+  fooAsdfLayoutRoute: fooAsdfLayoutRouteWithChildren,
+  fooAsdfanotherGroupRoute: fooAsdfanotherGroupRouteWithChildren,
+  fooAsdfbarIdRoute: fooAsdfbarIdRoute,
+  fooAsdfbarLayoutAboutRoute: fooAsdfbarLayoutAboutRoute,
+  fooAsdfbarLayoutXyzLazyRoute: fooAsdfbarLayoutXyzLazyRoute,
+}
+
+const fooAsdfRouteWithChildren =
+  fooAsdfRoute._addFileChildren(fooAsdfRouteChildren)
+
 export interface FileRoutesByFullPath {
+  '/asdf': typeof fooAsdfLayoutRouteWithChildren
+  '/asdf/': typeof fooAsdfanotherGroupLayoutRouteWithChildren
   '/asdf/$id': typeof fooAsdfbarIdRoute
+  '/asdf/foo': typeof fooAsdfLayoutFooRoute
+  '/asdf/baz': typeof fooAsdfanotherGroupLayoutBazRoute
+  '/asdf/about': typeof fooAsdfbarLayoutAboutRoute
+  '/asdf/xyz': typeof fooAsdfbarLayoutXyzLazyRoute
 }
 
 export interface FileRoutesByTo {
+  '/asdf': typeof fooAsdfanotherGroupLayoutRouteWithChildren
   '/asdf/$id': typeof fooAsdfbarIdRoute
+  '/asdf/foo': typeof fooAsdfLayoutFooRoute
+  '/asdf/baz': typeof fooAsdfanotherGroupLayoutBazRoute
+  '/asdf/about': typeof fooAsdfbarLayoutAboutRoute
+  '/asdf/xyz': typeof fooAsdfbarLayoutXyzLazyRoute
 }
 
 export interface FileRoutesById {
   __root__: typeof rootRoute
-  '/asdf/$id': typeof fooAsdfbarIdRoute
+  '/(foo)/asdf': typeof fooAsdfRouteWithChildren
+  '/(foo)/asdf/_layout': typeof fooAsdfLayoutRouteWithChildren
+  '/(foo)/asdf/(another-group)': typeof fooAsdfanotherGroupRouteWithChildren
+  '/(foo)/asdf/(another-group)/_layout': typeof fooAsdfanotherGroupLayoutRouteWithChildren
+  '/(foo)/asdf/(bar)/$id': typeof fooAsdfbarIdRoute
+  '/(foo)/asdf/_layout/foo': typeof fooAsdfLayoutFooRoute
+  '/(foo)/asdf/(another-group)/_layout/baz': typeof fooAsdfanotherGroupLayoutBazRoute
+  '/(foo)/asdf/(bar)/_layout/about': typeof fooAsdfbarLayoutAboutRoute
+  '/(foo)/asdf/(bar)/_layout/xyz': typeof fooAsdfbarLayoutXyzLazyRoute
 }
 
 export interface FileRouteTypes {
   fileRoutesByFullPath: FileRoutesByFullPath
-  fullPaths: '/asdf/$id'
+  fullPaths:
+    | '/asdf'
+    | '/asdf/'
+    | '/asdf/$id'
+    | '/asdf/foo'
+    | '/asdf/baz'
+    | '/asdf/about'
+    | '/asdf/xyz'
   fileRoutesByTo: FileRoutesByTo
-  to: '/asdf/$id'
-  id: '__root__' | '/asdf/$id'
+  to:
+    | '/asdf'
+    | '/asdf/$id'
+    | '/asdf/foo'
+    | '/asdf/baz'
+    | '/asdf/about'
+    | '/asdf/xyz'
+  id:
+    | '__root__'
+    | '/(foo)/asdf'
+    | '/(foo)/asdf/_layout'
+    | '/(foo)/asdf/(another-group)'
+    | '/(foo)/asdf/(another-group)/_layout'
+    | '/(foo)/asdf/(bar)/$id'
+    | '/(foo)/asdf/_layout/foo'
+    | '/(foo)/asdf/(another-group)/_layout/baz'
+    | '/(foo)/asdf/(bar)/_layout/about'
+    | '/(foo)/asdf/(bar)/_layout/xyz'
   fileRoutesById: FileRoutesById
 }
 
 export interface RootRouteChildren {
-  fooAsdfbarIdRoute: typeof fooAsdfbarIdRoute
+  fooAsdfRoute: typeof fooAsdfRouteWithChildren
 }
 
 const rootRouteChildren: RootRouteChildren = {
-  fooAsdfbarIdRoute: fooAsdfbarIdRoute,
+  fooAsdfRoute: fooAsdfRouteWithChildren,
 }
 
 export const routeTree = rootRoute
@@ -78,11 +294,59 @@ export const routeTree = rootRoute
     "__root__": {
       "filePath": "__root.tsx",
       "children": [
-        "/asdf/$id"
+        "/(foo)/asdf"
       ]
     },
-    "/asdf/$id": {
-      "filePath": "(foo)/asdf/(bar)/$id.tsx"
+    "/(foo)/asdf": {
+      "filePath": "(foo)/asdf",
+      "children": [
+        "/(foo)/asdf/_layout",
+        "/(foo)/asdf/(another-group)",
+        "/(foo)/asdf/(bar)/$id",
+        "/(foo)/asdf/(bar)/_layout/about",
+        "/(foo)/asdf/(bar)/_layout/xyz"
+      ]
+    },
+    "/(foo)/asdf/_layout": {
+      "filePath": "(foo)/asdf/_layout.tsx",
+      "parent": "/(foo)/asdf",
+      "children": [
+        "/(foo)/asdf/_layout/foo"
+      ]
+    },
+    "/(foo)/asdf/(another-group)": {
+      "filePath": "(foo)/asdf/(another-group)",
+      "parent": "/(foo)/asdf",
+      "children": [
+        "/(foo)/asdf/(another-group)/_layout"
+      ]
+    },
+    "/(foo)/asdf/(another-group)/_layout": {
+      "filePath": "(foo)/asdf/(another-group)/_layout.tsx",
+      "parent": "/(foo)/asdf/(another-group)",
+      "children": [
+        "/(foo)/asdf/(another-group)/_layout/baz"
+      ]
+    },
+    "/(foo)/asdf/(bar)/$id": {
+      "filePath": "(foo)/asdf/(bar)/$id.tsx",
+      "parent": "/(foo)/asdf"
+    },
+    "/(foo)/asdf/_layout/foo": {
+      "filePath": "(foo)/asdf/_layout.foo.tsx",
+      "parent": "/(foo)/asdf/_layout"
+    },
+    "/(foo)/asdf/(another-group)/_layout/baz": {
+      "filePath": "(foo)/asdf/(another-group)/_layout.baz.tsx",
+      "parent": "/(foo)/asdf/(another-group)/_layout"
+    },
+    "/(foo)/asdf/(bar)/_layout/about": {
+      "filePath": "(foo)/asdf/(bar)/_layout.about.tsx",
+      "parent": "/(foo)/asdf"
+    },
+    "/(foo)/asdf/(bar)/_layout/xyz": {
+      "filePath": "(foo)/asdf/(bar)/_layout.xyz.lazy.tsx",
+      "parent": "/(foo)/asdf"
     }
   }
 }
diff --git a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.baz.tsx b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.baz.tsx
new file mode 100644
index 000000000..ce8ed9a54
--- /dev/null
+++ b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.baz.tsx
@@ -0,0 +1,7 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/(foo)/asdf/(another-group)/_layout/baz')(
+  {
+    component: () => <div>Hello /(foo)/asdf/(another-group)/_layout/baz!</div>,
+  },
+)
diff --git a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.tsx b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.tsx
new file mode 100644
index 000000000..c2e5c502f
--- /dev/null
+++ b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(another-group)/_layout.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/(foo)/asdf/(another-group)/_layout')({
+  component: () => <div>Hello /(foo)/asdf/(another-group)/_layout!</div>,
+})
diff --git a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.about.tsx b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.about.tsx
new file mode 100644
index 000000000..06daaef4e
--- /dev/null
+++ b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.about.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/(foo)/asdf/(bar)/_layout/about')({
+  component: () => <div>Hello /(foo)/asdf/(bar)/_layout/about!</div>,
+})
diff --git a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.xyz.lazy.tsx b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.xyz.lazy.tsx
new file mode 100644
index 000000000..955cd7f9b
--- /dev/null
+++ b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/(bar)/_layout.xyz.lazy.tsx
@@ -0,0 +1,5 @@
+import { createLazyFileRoute } from '@tanstack/react-router'
+
+export const Route = createLazyFileRoute('/(foo)/asdf/(bar)/_layout/xyz')({
+  component: () => <div>Hello /(foo)/asdf/(bar)/_layout/xyz!</div>,
+})
diff --git a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.foo.tsx b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.foo.tsx
new file mode 100644
index 000000000..a09050527
--- /dev/null
+++ b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.foo.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/(foo)/asdf/_layout/foo')({
+  component: () => <div>Hello /(foo)/asdf/_layout/foo!</div>,
+})
diff --git a/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.tsx b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.tsx
new file mode 100644
index 000000000..681728467
--- /dev/null
+++ b/packages/router-generator/tests/generator/route-groups/routes/(foo)/asdf/_layout.tsx
@@ -0,0 +1,5 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/(foo)/asdf/_layout')({
+  component: () => <div>Hello /(foo)/asdf/_layout!</div>,
+})