diff --git a/.github/workflows/codspeed.yml b/.github/workflows/codspeed.yml
new file mode 100644
index 00000000000..549ec09d8fe
--- /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 00000000000..c9416967ea7
--- /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 00000000000..7db90c0f364
--- /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 {index}
+
+ ))
+
+ const rootScore =
+ selectedParams.reduce((sum, value) => sum + value, 0) +
+ selectedSearch.reduce((sum, value) => sum + value, 0)
+
+ return (
+
+
{rootScore}
+
{links}
+
+
+ )
+ },
+ })
+
+ const idRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ path: '/$id',
+ validateSearch: (search: Record) => ({
+ 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()
+
+ const done = new Promise((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 00000000000..256a46bcea3
--- /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 00000000000..c32a0fa9bf6
--- /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 00000000000..8490f273324
--- /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 (
+
+
{rootScore()}
+
+ {Array.from({ length: LINK_COUNT }, (_, index) => (
+
+ Link {index}
+
+ ))}
+
+
+ )
+}
+
+function setupBenchmark() {
+ const rootRoute = createRootRoute()
+ const idRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ path: '/$id',
+ validateSearch: (search: Record) => ({
+ n: parseIntOrZero(search.n),
+ }),
+ })
+
+ const routeTree = rootRoute.addChildren([idRoute])
+
+ const router = createRouter({
+ routeTree,
+ history: createMemoryHistory({
+ initialEntries: ['/0?n=0'],
+ }),
+ })
+
+ const mounted = render(() => (
+
+ {() => }
+
+ ))
+
+ const done = new Promise((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 00000000000..db443a516ad
--- /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 00000000000..b088161598e
--- /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 00000000000..f002d7159ad
--- /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) => ({
+ 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((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 00000000000..21a9f3d0cf6
--- /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 5b6c19258f9..dfaaf8e4d36 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 4580b961153..b3b0e2dc514 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 fe84aeb0379..2810feb95a7 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/*'