diff --git a/.github/workflows/codspeed.yml b/.github/workflows/codspeed.yml
new file mode 100644
index 0000000000..549ec09d8f
--- /dev/null
+++ b/.github/workflows/codspeed.yml
@@ -0,0 +1,34 @@
+name: CodSpeed
+
+on:
+  # disable for now
+  # pull_request:
+  # push:
+  #   branches: [main]
+  workflow_dispatch:
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.event.number || github.ref }}
+  cancel-in-progress: true
+
+permissions:
+  contents: read
+  id-token: write
+
+jobs:
+  client-nav:
+    name: Client Nav Benchmarks
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v6.0.1
+
+      - name: Setup Tools
+        uses: tanstack/config/.github/setup@main
+
+      - name: Run Client Navigation Benchmarks
+        uses: CodSpeedHQ/action@v4
+        with:
+          mode: simulation
+          run: |
+            CI=1 NX_DAEMON=false pnpm nx run tanstack-router-benchmark-client-nav:bench --outputStyle=stream --skipNxCache --skipRemoteCache
diff --git a/benchmarks/client-nav/package.json b/benchmarks/client-nav/package.json
new file mode 100644
index 0000000000..c9416967ea
--- /dev/null
+++ b/benchmarks/client-nav/package.json
@@ -0,0 +1,39 @@
+{
+  "name": "tanstack-router-benchmark-client-nav",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "bench": "pnpm run bench:react && pnpm run bench:solid && pnpm run bench:vue",
+    "bench:react": "NODE_ENV=production vitest bench --run --config react/vitest.config.ts react/client-nav.bench.tsx",
+    "bench:solid": "NODE_ENV=production vitest bench --run --config solid/vitest.config.ts solid/client-nav.bench.tsx",
+    "bench:vue": "NODE_ENV=production vitest bench --run --config vue/vitest.config.ts vue/client-nav.bench.ts"
+  },
+  "dependencies": {
+    "@tanstack/react-router": "workspace:*",
+    "@tanstack/solid-router": "workspace:*",
+    "@tanstack/vue-router": "workspace:*",
+    "react": "^19.0.0",
+    "react-dom": "^19.0.0",
+    "solid-js": "^1.9.10",
+    "vue": "^3.5.25"
+  },
+  "devDependencies": {
+    "@codspeed/vitest-plugin": "^5.0.1",
+    "@vitejs/plugin-react": "^4.3.4",
+    "@vitejs/plugin-vue": "^6.0.1",
+    "typescript": "^5.9.3",
+    "vite": "^7.3.1",
+    "vite-plugin-solid": "^2.11.10",
+    "vitest": "^4.0.17"
+  },
+  "nx": {
+    "targets": {
+      "bench": {
+        "dependsOn": [
+          "^build"
+        ],
+        "cache": false
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/benchmarks/client-nav/react/client-nav.bench.tsx b/benchmarks/client-nav/react/client-nav.bench.tsx
new file mode 100644
index 0000000000..7db90c0f36
--- /dev/null
+++ b/benchmarks/client-nav/react/client-nav.bench.tsx
@@ -0,0 +1,174 @@
+import { createRoot } from 'react-dom/client'
+import { bench } from 'vitest'
+import { useEffect } from 'react'
+import {
+  Link,
+  Outlet,
+  RouterProvider,
+  createMemoryHistory,
+  createRootRoute,
+  createRoute,
+  createRouter,
+} from '@tanstack/react-router'
+
+import {
+  HOOK_COUNT,
+  LINK_COUNT,
+  TARGET_ID,
+  TIMEOUT,
+  heavySelect,
+  parseIntOrZero,
+} from '../shared'
+
+function setupBenchmark() {
+  const rootRoute = createRootRoute({
+    component: () => {
+      const selectedParams = Array.from({ length: HOOK_COUNT }, (_, index) =>
+        rootRoute.useParams({
+          strict: false,
+          select: (params) => heavySelect(params.id, index),
+        }),
+      )
+
+      const selectedSearch = Array.from({ length: HOOK_COUNT }, (_, index) =>
+        rootRoute.useSearch({
+          strict: false,
+          select: (search) => heavySelect(search.n, index + HOOK_COUNT),
+        }),
+      )
+
+      const links = Array.from({ length: LINK_COUNT }, (_, index) => (
+        <Link
+          key={index}
+          to="/$id"
+          params={{ id: String(index) }}
+          search={{ n: index }}
+        >
+          Link {index}
+        </Link>
+      ))
+
+      const rootScore =
+        selectedParams.reduce((sum, value) => sum + value, 0) +
+        selectedSearch.reduce((sum, value) => sum + value, 0)
+
+      return (
+        <div>
+          <div style={{ display: 'none' }}>{rootScore}</div>
+          <div style={{ display: 'none' }}>{links}</div>
+          <Outlet />
+        </div>
+      )
+    },
+  })
+
+  const idRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/$id',
+    validateSearch: (search: Record<string, unknown>) => ({
+      n: parseIntOrZero(search.n),
+    }),
+    component: () => {
+      const id = idRoute.useParams({
+        select: (params) => parseIntOrZero(params.id),
+      })
+      const n = idRoute.useSearch({
+        select: (search) => parseIntOrZero(search.n),
+      })
+      const navigate = idRoute.useNavigate()
+
+      useEffect(() => {
+        if (id < TARGET_ID) {
+          const next = id + 1
+          void navigate({
+            to: '/$id',
+            params: { id: String(next) },
+            search: { n: next },
+          })
+        }
+      }, [id, n, navigate])
+
+      return null
+    },
+  })
+
+  const routeTree = rootRoute.addChildren([idRoute])
+
+  const router = createRouter({
+    routeTree,
+    history: createMemoryHistory({
+      initialEntries: ['/0?n=0'],
+    }),
+  })
+
+  const container = document.createElement('div')
+  document.body.appendChild(container)
+  const reactRoot = createRoot(container)
+
+  reactRoot.render(<RouterProvider router={router} />)
+
+  const done = new Promise<void>((resolve, reject) => {
+    const expectedHref = `/${TARGET_ID}?n=${TARGET_ID}`
+
+    let settled = false
+    let unsubscribe = () => {}
+
+    const settle = (error?: Error) => {
+      if (settled) {
+        return
+      }
+
+      settled = true
+      window.clearTimeout(timeoutId)
+      unsubscribe()
+
+      if (error) {
+        reject(error)
+      } else {
+        resolve()
+      }
+    }
+
+    const timeoutId = window.setTimeout(() => {
+      settle(
+        new Error(
+          `React benchmark timed out at ${router.state.location.href}; expected ${expectedHref}`,
+        ),
+      )
+    }, TIMEOUT)
+
+    unsubscribe = router.subscribe('onResolved', (event) => {
+      if (event.toLocation.href === expectedHref) {
+        settle()
+      }
+    })
+
+    if (router.state.location.href === expectedHref) {
+      settle()
+    }
+  })
+
+  return {
+    done,
+    cleanup: () => {
+      reactRoot.unmount()
+      container.remove()
+    },
+  }
+}
+
+bench(
+  'client-nav.react.10-nav',
+  async () => {
+    const { done, cleanup } = setupBenchmark()
+
+    try {
+      await done
+    } finally {
+      cleanup()
+    }
+  },
+  {
+    throws: true,
+  },
+)
diff --git a/benchmarks/client-nav/react/vitest.config.ts b/benchmarks/client-nav/react/vitest.config.ts
new file mode 100644
index 0000000000..256a46bcea
--- /dev/null
+++ b/benchmarks/client-nav/react/vitest.config.ts
@@ -0,0 +1,17 @@
+import { defineConfig } from 'vitest/config'
+import react from '@vitejs/plugin-react'
+import codspeedPlugin from '@codspeed/vitest-plugin'
+
+export default defineConfig({
+  plugins: [react(), codspeedPlugin()],
+  resolve: {
+    conditions: ['browser'],
+  },
+  test: {
+    environment: 'jsdom',
+    include: ['react/**/*.bench.tsx'],
+    benchmark: {
+      include: ['react/**/*.bench.tsx'],
+    },
+  },
+})
diff --git a/benchmarks/client-nav/shared.ts b/benchmarks/client-nav/shared.ts
new file mode 100644
index 0000000000..c32a0fa9bf
--- /dev/null
+++ b/benchmarks/client-nav/shared.ts
@@ -0,0 +1,29 @@
+export const LINK_COUNT = 20
+export const HOOK_COUNT = 20
+export const TARGET_ID = 10
+export const TIMEOUT = 10_000
+
+export function heavySelect(
+  seed: string | number | undefined,
+  salt: number,
+): number {
+  let value =
+    typeof seed === 'number' ? seed : Number.parseInt(seed ?? '0', 10) || 0
+
+  for (let i = 0; i < 5; i++) {
+    value = (value * 33 + salt + i) % 104_729
+    value ^= (value << 5) & 0xffff
+    value &= 0x7fffffff
+  }
+
+  return value
+}
+
+export function parseIntOrZero(value: unknown): number {
+  if (typeof value === 'number') {
+    return Number.isFinite(value) ? value : 0
+  }
+
+  const parsed = Number.parseInt(String(value ?? '0'), 10)
+  return Number.isFinite(parsed) ? parsed : 0
+}
diff --git a/benchmarks/client-nav/solid/client-nav.bench.tsx b/benchmarks/client-nav/solid/client-nav.bench.tsx
new file mode 100644
index 0000000000..8490f27332
--- /dev/null
+++ b/benchmarks/client-nav/solid/client-nav.bench.tsx
@@ -0,0 +1,170 @@
+import { render } from '@solidjs/testing-library'
+import { bench } from 'vitest'
+import {
+  Link,
+  RouterContextProvider,
+  createMemoryHistory,
+  createRootRoute,
+  createRoute,
+  createRouter,
+  useParams,
+  useSearch,
+} from '@tanstack/solid-router'
+
+import {
+  HOOK_COUNT,
+  LINK_COUNT,
+  TARGET_ID,
+  TIMEOUT,
+  heavySelect,
+  parseIntOrZero,
+} from '../shared'
+
+function BenchmarkComponent() {
+  const selectedParams = Array.from({ length: HOOK_COUNT }, (_, index) =>
+    useParams({
+      from: '/$id',
+      strict: false,
+      shouldThrow: false,
+      select: (params) => heavySelect(params.id, index),
+    }),
+  )
+
+  const selectedSearch = Array.from({ length: HOOK_COUNT }, (_, index) =>
+    useSearch({
+      from: '/$id',
+      strict: false,
+      shouldThrow: false,
+      select: (search) => heavySelect(search.n, index + HOOK_COUNT),
+    }),
+  )
+
+  const selectedId = useParams({
+    from: '/$id',
+    strict: false,
+    shouldThrow: false,
+    select: (params) => parseIntOrZero(params.id),
+  })
+
+  const selectedN = useSearch({
+    from: '/$id',
+    strict: false,
+    shouldThrow: false,
+    select: (search) => parseIntOrZero(search.n),
+  })
+
+  const rootScore = () => {
+    const paramsScore = selectedParams.reduce(
+      (sum, accessor) => sum + accessor(),
+      0,
+    )
+    const searchScore = selectedSearch.reduce(
+      (sum, accessor) => sum + accessor(),
+      0,
+    )
+    return paramsScore + searchScore + selectedId() + selectedN()
+  }
+
+  return (
+    <div>
+      <div style={{ display: 'none' }}>{rootScore()}</div>
+      <div style={{ display: 'none' }}>
+        {Array.from({ length: LINK_COUNT }, (_, index) => (
+          <Link to="/$id" params={{ id: String(index) }} search={{ n: index }}>
+            Link {index}
+          </Link>
+        ))}
+      </div>
+    </div>
+  )
+}
+
+function setupBenchmark() {
+  const rootRoute = createRootRoute()
+  const idRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/$id',
+    validateSearch: (search: Record<string, unknown>) => ({
+      n: parseIntOrZero(search.n),
+    }),
+  })
+
+  const routeTree = rootRoute.addChildren([idRoute])
+
+  const router = createRouter({
+    routeTree,
+    history: createMemoryHistory({
+      initialEntries: ['/0?n=0'],
+    }),
+  })
+
+  const mounted = render(() => (
+    <RouterContextProvider router={router}>
+      {() => <BenchmarkComponent />}
+    </RouterContextProvider>
+  ))
+
+  const done = new Promise<void>((resolve, reject) => {
+    const expectedHref = `/${TARGET_ID}?n=${TARGET_ID}`
+
+    const timeoutId = window.setTimeout(() => {
+      reject(
+        new Error(
+          `Solid benchmark timed out at ${router.state.location.href}; expected ${expectedHref}`,
+        ),
+      )
+    }, TIMEOUT)
+
+    void (async () => {
+      try {
+        await router.load()
+
+        for (let next = 1; next <= TARGET_ID; next++) {
+          await router.navigate({
+            to: '/$id',
+            params: { id: String(next) },
+            search: { n: next },
+          })
+        }
+
+        if (router.state.location.href !== expectedHref) {
+          reject(
+            new Error(
+              `Solid benchmark stopped at ${router.state.location.href}; expected ${expectedHref}`,
+            ),
+          )
+          return
+        }
+
+        resolve()
+      } catch (error) {
+        reject(error)
+      } finally {
+        window.clearTimeout(timeoutId)
+      }
+    })()
+  })
+
+  return {
+    done,
+    cleanup: () => {
+      mounted.unmount()
+    },
+  }
+}
+
+bench(
+  'client-nav.solid.10-nav',
+  async () => {
+    const { done, cleanup } = setupBenchmark()
+
+    try {
+      await done
+    } finally {
+      cleanup()
+    }
+  },
+  {
+    throws: true,
+  },
+)
diff --git a/benchmarks/client-nav/solid/vitest.config.ts b/benchmarks/client-nav/solid/vitest.config.ts
new file mode 100644
index 0000000000..db443a516a
--- /dev/null
+++ b/benchmarks/client-nav/solid/vitest.config.ts
@@ -0,0 +1,22 @@
+import { defineConfig } from 'vitest/config'
+import solid from 'vite-plugin-solid'
+import codspeedPlugin from '@codspeed/vitest-plugin'
+
+export default defineConfig({
+  plugins: [solid({ ssr: false, dev: false, hot: false }), codspeedPlugin()],
+  resolve: {
+    conditions: ['solid', 'browser'],
+  },
+  test: {
+    environment: 'jsdom',
+    include: ['solid/**/*.bench.tsx'],
+    benchmark: {
+      include: ['solid/**/*.bench.tsx'],
+    },
+    server: {
+      deps: {
+        inline: [/@solidjs/, /@tanstack\/solid-store/],
+      },
+    },
+  },
+})
diff --git a/benchmarks/client-nav/tsconfig.json b/benchmarks/client-nav/tsconfig.json
new file mode 100644
index 0000000000..b088161598
--- /dev/null
+++ b/benchmarks/client-nav/tsconfig.json
@@ -0,0 +1,13 @@
+{
+  "compilerOptions": {
+    "strict": true,
+    "esModuleInterop": true,
+    "target": "ESNext",
+    "module": "ESNext",
+    "moduleResolution": "Bundler",
+    "jsx": "preserve",
+    "skipLibCheck": true,
+    "types": ["vite/client", "vitest/globals"]
+  },
+  "exclude": ["node_modules", "dist"]
+}
diff --git a/benchmarks/client-nav/vue/client-nav.bench.ts b/benchmarks/client-nav/vue/client-nav.bench.ts
new file mode 100644
index 0000000000..f002d7159a
--- /dev/null
+++ b/benchmarks/client-nav/vue/client-nav.bench.ts
@@ -0,0 +1,185 @@
+import { createApp, defineComponent, h, watchEffect } from 'vue'
+import { bench } from 'vitest'
+import {
+  Link,
+  Outlet,
+  RouterProvider,
+  createMemoryHistory,
+  createRootRoute,
+  createRoute,
+  createRouter,
+} from '@tanstack/vue-router'
+
+import {
+  HOOK_COUNT,
+  LINK_COUNT,
+  TARGET_ID,
+  TIMEOUT,
+  heavySelect,
+  parseIntOrZero,
+} from '../shared'
+
+function setupBenchmark() {
+  const RootComponent = defineComponent(() => {
+    const selectedParams = Array.from({ length: HOOK_COUNT }, (_, index) =>
+      rootRoute.useParams({
+        strict: false,
+        select: (params) => heavySelect(params.id, index),
+      }),
+    )
+
+    const selectedSearch = Array.from({ length: HOOK_COUNT }, (_, index) =>
+      rootRoute.useSearch({
+        strict: false,
+        select: (search) => heavySelect(search.n, index + HOOK_COUNT),
+      }),
+    )
+
+    return () => {
+      const rootScore =
+        selectedParams.reduce((sum, current) => sum + current.value, 0) +
+        selectedSearch.reduce((sum, current) => sum + current.value, 0)
+
+      return h('div', [
+        h('div', { style: 'display: none' }, String(rootScore)),
+        h(
+          'div',
+          { style: 'display: none' },
+          Array.from({ length: LINK_COUNT }, (_, index) =>
+            h(
+              Link,
+              {
+                to: '/$id',
+                params: { id: String(index) },
+                search: { n: index },
+              },
+              {
+                default: () => `Link ${index}`,
+              },
+            ),
+          ),
+        ),
+        h(Outlet),
+      ])
+    }
+  })
+
+  const IdComponent = defineComponent(() => {
+    const id = idRoute.useParams({
+      select: (params) => parseIntOrZero(params.id),
+    })
+    const n = idRoute.useSearch({
+      select: (search) => parseIntOrZero(search.n),
+    })
+    const navigate = idRoute.useNavigate()
+
+    watchEffect(() => {
+      const currentId = id.value
+      void n.value
+
+      if (currentId < TARGET_ID) {
+        const next = currentId + 1
+        void navigate({
+          to: '/$id',
+          params: { id: String(next) },
+          search: { n: next },
+        })
+      }
+    })
+
+    return () => null
+  })
+
+  const rootRoute = createRootRoute({ component: RootComponent })
+  const idRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/$id',
+    validateSearch: (search: Record<string, unknown>) => ({
+      n: parseIntOrZero(search.n),
+    }),
+    component: IdComponent,
+  })
+
+  const routeTree = rootRoute.addChildren([idRoute])
+
+  const router = createRouter({
+    routeTree,
+    history: createMemoryHistory({
+      initialEntries: ['/0?n=0'],
+    }),
+  })
+
+  const container = document.createElement('div')
+  document.body.appendChild(container)
+
+  const app = createApp({
+    render: () => h(RouterProvider, { router }),
+  })
+
+  app.mount(container)
+
+  const done = new Promise<void>((resolve, reject) => {
+    const expectedHref = `/${TARGET_ID}?n=${TARGET_ID}`
+
+    let settled = false
+    let unsubscribe = () => {}
+
+    const settle = (error?: Error) => {
+      if (settled) {
+        return
+      }
+
+      settled = true
+      window.clearTimeout(timeoutId)
+      unsubscribe()
+
+      if (error) {
+        reject(error)
+      } else {
+        resolve()
+      }
+    }
+
+    const timeoutId = window.setTimeout(() => {
+      settle(
+        new Error(
+          `Vue benchmark timed out at ${router.state.location.href}; expected ${expectedHref}`,
+        ),
+      )
+    }, TIMEOUT)
+
+    unsubscribe = router.subscribe('onResolved', (event) => {
+      if (event.toLocation.href === expectedHref) {
+        settle()
+      }
+    })
+
+    if (router.state.location.href === expectedHref) {
+      settle()
+    }
+  })
+
+  return {
+    done,
+    cleanup: () => {
+      app.unmount()
+      container.remove()
+    },
+  }
+}
+
+bench(
+  'client-nav.vue.10-nav',
+  async () => {
+    const { done, cleanup } = setupBenchmark()
+
+    try {
+      await done
+    } finally {
+      cleanup()
+    }
+  },
+  {
+    throws: true,
+  },
+)
diff --git a/benchmarks/client-nav/vue/vitest.config.ts b/benchmarks/client-nav/vue/vitest.config.ts
new file mode 100644
index 0000000000..21a9f3d0cf
--- /dev/null
+++ b/benchmarks/client-nav/vue/vitest.config.ts
@@ -0,0 +1,17 @@
+import { defineConfig } from 'vitest/config'
+import vue from '@vitejs/plugin-vue'
+import codspeedPlugin from '@codspeed/vitest-plugin'
+
+export default defineConfig({
+  plugins: [vue(), codspeedPlugin()],
+  resolve: {
+    conditions: ['browser'],
+  },
+  test: {
+    environment: 'jsdom',
+    include: ['vue/**/*.bench.ts'],
+    benchmark: {
+      include: ['vue/**/*.bench.ts'],
+    },
+  },
+})
diff --git a/package.json b/package.json
index 5b6c19258f..dfaaf8e4d3 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
     "test:types": "nx affected --target=test:types --exclude=examples/**",
     "test:e2e": "nx run-many --target=test:e2e",
     "benchmark:bundle-size": "pnpm nx run tanstack-router-e2e-bundle-size:build",
+    "benchmark:client-nav": "pnpm nx run tanstack-router-benchmark-client-nav:bench",
     "build": "nx affected --target=build --exclude=e2e/** --exclude=examples/**",
     "build:all": "nx run-many --target=build --exclude=examples/** --exclude=e2e/**",
     "watch": "pnpm run build:all && nx watch --all -- pnpm run build:all",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4580b96115..b3b0e2dc51 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -158,6 +158,52 @@ importers:
         specifier: ^4.0.17
         version: 4.0.17(@types/node@25.0.9)(@vitest/ui@4.0.17)(jiti@2.6.1)(jsdom@25.0.1)(lightningcss@1.30.2)(msw@2.7.0(@types/node@25.0.9)(typescript@5.9.3))(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
 
+  benchmarks/client-nav:
+    dependencies:
+      '@tanstack/react-router':
+        specifier: workspace:*
+        version: link:../../packages/react-router
+      '@tanstack/solid-router':
+        specifier: workspace:*
+        version: link:../../packages/solid-router
+      '@tanstack/vue-router':
+        specifier: workspace:*
+        version: link:../../packages/vue-router
+      react:
+        specifier: ^19.2.3
+        version: 19.2.3
+      react-dom:
+        specifier: ^19.2.3
+        version: 19.2.3(react@19.2.3)
+      solid-js:
+        specifier: 1.9.10
+        version: 1.9.10
+      vue:
+        specifier: ^3.5.25
+        version: 3.5.25(typescript@5.9.3)
+    devDependencies:
+      '@codspeed/vitest-plugin':
+        specifier: ^5.0.1
+        version: 5.2.0(tinybench@2.9.0)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))(vitest@4.0.17)
+      '@vitejs/plugin-react':
+        specifier: ^4.3.4
+        version: 4.7.0(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))
+      '@vitejs/plugin-vue':
+        specifier: ^6.0.1
+        version: 6.0.3(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.3))
+      typescript:
+        specifier: ^5.9.3
+        version: 5.9.3
+      vite:
+        specifier: ^7.3.1
+        version: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
+      vite-plugin-solid:
+        specifier: ^2.11.10
+        version: 2.11.10(@testing-library/jest-dom@6.6.3)(solid-js@1.9.10)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))
+      vitest:
+        specifier: ^4.0.17
+        version: 4.0.17(@types/node@25.0.9)(@vitest/ui@4.0.17)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.2)(msw@2.7.0(@types/node@25.0.9)(typescript@5.9.3))(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
+
   e2e/bundle-size:
     dependencies:
       '@tanstack/react-router':
@@ -13264,6 +13310,16 @@ packages:
     cpu: [x64]
     os: [win32]
 
+  '@codspeed/core@5.2.0':
+    resolution: {integrity: sha512-CmDhpWjcOJg2iBOQ/BmBnSBq8qxlM3r4h8uvYDkoUaba+EKRT3T73BZtKuml/48jZMsB+4/FG2UbTBinDWtuvw==}
+
+  '@codspeed/vitest-plugin@5.2.0':
+    resolution: {integrity: sha512-soXKIQBqJzjVQyWRwe2HNfhCaBgxhG25m8+PI3F5zFFsV3FQxMJXHsMECNtrgm+SRiCiWv/OFTcfCMZRy4nKtw==}
+    peerDependencies:
+      tinybench: '>=2.9.0'
+      vite: ^7.3.1
+      vitest: ^3.2 || ^4
+
   '@colors/colors@1.5.0':
     resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
     engines: {node: '>=0.1.90'}
@@ -20552,6 +20608,10 @@ packages:
     resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
     engines: {node: '>=10'}
 
+  find-up@6.3.0:
+    resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
   find-up@7.0.0:
     resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==}
     engines: {node: '>=18'}
@@ -25703,6 +25763,24 @@ snapshots:
   '@cloudflare/workerd-windows-64@1.20251118.0':
     optional: true
 
+  '@codspeed/core@5.2.0':
+    dependencies:
+      axios: 1.13.2
+      find-up: 6.3.0
+      form-data: 4.0.5
+      node-gyp-build: 4.8.4
+    transitivePeerDependencies:
+      - debug
+
+  '@codspeed/vitest-plugin@5.2.0(tinybench@2.9.0)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))(vitest@4.0.17)':
+    dependencies:
+      '@codspeed/core': 5.2.0
+      tinybench: 2.9.0
+      vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
+      vitest: 4.0.17(@types/node@25.0.9)(@vitest/ui@4.0.17)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.2)(msw@2.7.0(@types/node@25.0.9)(typescript@5.9.3))(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
+    transitivePeerDependencies:
+      - debug
+
   '@colors/colors@1.5.0':
     optional: true
 
@@ -31273,7 +31351,7 @@ snapshots:
       sirv: 3.0.2
       tinyglobby: 0.2.15
       tinyrainbow: 3.0.3
-      vitest: 4.0.17(@types/node@25.0.9)(@vitest/ui@4.0.17)(jiti@2.6.1)(jsdom@25.0.1)(lightningcss@1.30.2)(msw@2.7.0(@types/node@25.0.9)(typescript@5.9.3))(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
+      vitest: 4.0.17(@types/node@25.0.9)(@vitest/ui@4.0.17)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.2)(msw@2.7.0(@types/node@25.0.9)(typescript@5.9.3))(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
 
   '@vitest/utils@3.2.4':
     dependencies:
@@ -33957,6 +34035,11 @@ snapshots:
       locate-path: 6.0.0
       path-exists: 4.0.0
 
+  find-up@6.3.0:
+    dependencies:
+      locate-path: 7.2.0
+      path-exists: 5.0.0
+
   find-up@7.0.0:
     dependencies:
       locate-path: 7.2.0
@@ -38599,6 +38682,45 @@ snapshots:
       - tsx
       - yaml
 
+  vitest@4.0.17(@types/node@25.0.9)(@vitest/ui@4.0.17)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.2)(msw@2.7.0(@types/node@25.0.9)(typescript@5.9.3))(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1):
+    dependencies:
+      '@vitest/expect': 4.0.17
+      '@vitest/mocker': 4.0.17(msw@2.7.0(@types/node@25.0.9)(typescript@5.9.3))(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))
+      '@vitest/pretty-format': 4.0.17
+      '@vitest/runner': 4.0.17
+      '@vitest/snapshot': 4.0.17
+      '@vitest/spy': 4.0.17
+      '@vitest/utils': 4.0.17
+      es-module-lexer: 1.7.0
+      expect-type: 1.2.2
+      magic-string: 0.30.21
+      obug: 2.1.1
+      pathe: 2.0.3
+      picomatch: 4.0.3
+      std-env: 3.10.0
+      tinybench: 2.9.0
+      tinyexec: 1.0.2
+      tinyglobby: 0.2.15
+      tinyrainbow: 3.0.3
+      vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.97.2)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
+      why-is-node-running: 2.3.0
+    optionalDependencies:
+      '@types/node': 25.0.9
+      '@vitest/ui': 4.0.17(vitest@4.0.17)
+      jsdom: 27.0.0(postcss@8.5.6)
+    transitivePeerDependencies:
+      - jiti
+      - less
+      - lightningcss
+      - msw
+      - sass
+      - sass-embedded
+      - stylus
+      - sugarss
+      - terser
+      - tsx
+      - yaml
+
   vscode-uri@3.0.8: {}
 
   vue-component-type-helpers@2.2.12: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index fe84aeb037..2810feb95a 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -12,6 +12,7 @@ packages:
   - 'examples/react/router-monorepo-simple-lazy/packages/*'
   - 'e2e/e2e-utils'
   - 'e2e/bundle-size'
+  - 'benchmarks/*'
   - 'e2e/react-router/*'
   - 'e2e/solid-router/*'
   - 'e2e/vue-router/*'
