From a5eb42099f672c9e1537436f2fe26c19a27ada26 Mon Sep 17 00:00:00 2001
From: Jamie Davenport <1329874+jamiedavenport@users.noreply.github.com>
Date: Mon, 20 Oct 2025 21:20:34 +0100
Subject: [PATCH 1/2] Setup otel example

---
 examples/react/start-otel/.gitignore          |  20 +
 examples/react/start-otel/.prettierignore     |   4 +
 .../react/start-otel/.vscode/settings.json    |  11 +
 examples/react/start-otel/README.md           |  72 +++
 examples/react/start-otel/docker-compose.yml  |  14 +
 examples/react/start-otel/package.json        |  36 ++
 examples/react/start-otel/postcss.config.mjs  |   6 +
 .../public/android-chrome-192x192.png         | Bin 0 -> 29964 bytes
 .../public/android-chrome-512x512.png         | Bin 0 -> 109271 bytes
 .../start-otel/public/apple-touch-icon.png    | Bin 0 -> 27246 bytes
 .../react/start-otel/public/favicon-16x16.png | Bin 0 -> 832 bytes
 .../react/start-otel/public/favicon-32x32.png | Bin 0 -> 2115 bytes
 examples/react/start-otel/public/favicon.ico  | Bin 0 -> 15406 bytes
 examples/react/start-otel/public/favicon.png  | Bin 0 -> 1507 bytes
 .../react/start-otel/public/site.webmanifest  |  19 +
 .../src/components/DefaultCatchBoundary.tsx   |  53 ++
 .../start-otel/src/components/NotFound.tsx    |  25 +
 .../start-otel/src/components/PostError.tsx   |   6 +
 .../start-otel/src/components/UserError.tsx   |   6 +
 examples/react/start-otel/src/otel.ts         |  16 +
 .../react/start-otel/src/routeTree.gen.ts     | 447 +++++++++++++++
 examples/react/start-otel/src/router.tsx      |  15 +
 .../react/start-otel/src/routes/__root.tsx    | 131 +++++
 .../start-otel/src/routes/_pathlessLayout.tsx |  16 +
 .../routes/_pathlessLayout/_nested-layout.tsx |  34 ++
 .../_nested-layout/route-a.tsx                |  11 +
 .../_nested-layout/route-b.tsx                |  11 +
 .../src/routes/api/users.$userId.ts           |  32 ++
 .../react/start-otel/src/routes/api/users.ts  |  63 ++
 .../src/routes/customScript[.]js.ts           |  15 +
 .../react/start-otel/src/routes/deferred.tsx  |  62 ++
 .../react/start-otel/src/routes/index.tsx     |  13 +
 .../start-otel/src/routes/posts.$postId.tsx   |  34 ++
 .../start-otel/src/routes/posts.index.tsx     |   9 +
 .../react/start-otel/src/routes/posts.tsx     |  38 ++
 .../src/routes/posts_.$postId.deep.tsx        |  29 +
 .../react/start-otel/src/routes/redirect.tsx  |   9 +
 .../start-otel/src/routes/users.$userId.tsx   |  45 ++
 .../start-otel/src/routes/users.index.tsx     |  19 +
 .../react/start-otel/src/routes/users.tsx     |  49 ++
 examples/react/start-otel/src/server.ts       |  21 +
 examples/react/start-otel/src/styles/app.css  |  22 +
 .../src/utils/loggingMiddleware.tsx           |  41 ++
 examples/react/start-otel/src/utils/posts.tsx |  53 ++
 examples/react/start-otel/src/utils/seo.ts    |  33 ++
 examples/react/start-otel/src/utils/tracer.ts |   3 +
 examples/react/start-otel/src/utils/users.tsx |   5 +
 examples/react/start-otel/tailwind.config.mjs |   4 +
 examples/react/start-otel/tsconfig.json       |  22 +
 examples/react/start-otel/vite.config.ts      |  19 +
 pnpm-lock.yaml                                | 540 +++++++++++++++++-
 51 files changed, 2103 insertions(+), 30 deletions(-)
 create mode 100644 examples/react/start-otel/.gitignore
 create mode 100644 examples/react/start-otel/.prettierignore
 create mode 100644 examples/react/start-otel/.vscode/settings.json
 create mode 100644 examples/react/start-otel/README.md
 create mode 100644 examples/react/start-otel/docker-compose.yml
 create mode 100644 examples/react/start-otel/package.json
 create mode 100644 examples/react/start-otel/postcss.config.mjs
 create mode 100644 examples/react/start-otel/public/android-chrome-192x192.png
 create mode 100644 examples/react/start-otel/public/android-chrome-512x512.png
 create mode 100644 examples/react/start-otel/public/apple-touch-icon.png
 create mode 100644 examples/react/start-otel/public/favicon-16x16.png
 create mode 100644 examples/react/start-otel/public/favicon-32x32.png
 create mode 100644 examples/react/start-otel/public/favicon.ico
 create mode 100644 examples/react/start-otel/public/favicon.png
 create mode 100644 examples/react/start-otel/public/site.webmanifest
 create mode 100644 examples/react/start-otel/src/components/DefaultCatchBoundary.tsx
 create mode 100644 examples/react/start-otel/src/components/NotFound.tsx
 create mode 100644 examples/react/start-otel/src/components/PostError.tsx
 create mode 100644 examples/react/start-otel/src/components/UserError.tsx
 create mode 100644 examples/react/start-otel/src/otel.ts
 create mode 100644 examples/react/start-otel/src/routeTree.gen.ts
 create mode 100644 examples/react/start-otel/src/router.tsx
 create mode 100644 examples/react/start-otel/src/routes/__root.tsx
 create mode 100644 examples/react/start-otel/src/routes/_pathlessLayout.tsx
 create mode 100644 examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout.tsx
 create mode 100644 examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-a.tsx
 create mode 100644 examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-b.tsx
 create mode 100644 examples/react/start-otel/src/routes/api/users.$userId.ts
 create mode 100644 examples/react/start-otel/src/routes/api/users.ts
 create mode 100644 examples/react/start-otel/src/routes/customScript[.]js.ts
 create mode 100644 examples/react/start-otel/src/routes/deferred.tsx
 create mode 100644 examples/react/start-otel/src/routes/index.tsx
 create mode 100644 examples/react/start-otel/src/routes/posts.$postId.tsx
 create mode 100644 examples/react/start-otel/src/routes/posts.index.tsx
 create mode 100644 examples/react/start-otel/src/routes/posts.tsx
 create mode 100644 examples/react/start-otel/src/routes/posts_.$postId.deep.tsx
 create mode 100644 examples/react/start-otel/src/routes/redirect.tsx
 create mode 100644 examples/react/start-otel/src/routes/users.$userId.tsx
 create mode 100644 examples/react/start-otel/src/routes/users.index.tsx
 create mode 100644 examples/react/start-otel/src/routes/users.tsx
 create mode 100644 examples/react/start-otel/src/server.ts
 create mode 100644 examples/react/start-otel/src/styles/app.css
 create mode 100644 examples/react/start-otel/src/utils/loggingMiddleware.tsx
 create mode 100644 examples/react/start-otel/src/utils/posts.tsx
 create mode 100644 examples/react/start-otel/src/utils/seo.ts
 create mode 100644 examples/react/start-otel/src/utils/tracer.ts
 create mode 100644 examples/react/start-otel/src/utils/users.tsx
 create mode 100644 examples/react/start-otel/tailwind.config.mjs
 create mode 100644 examples/react/start-otel/tsconfig.json
 create mode 100644 examples/react/start-otel/vite.config.ts

diff --git a/examples/react/start-otel/.gitignore b/examples/react/start-otel/.gitignore
new file mode 100644
index 0000000000..6ab0517d9f
--- /dev/null
+++ b/examples/react/start-otel/.gitignore
@@ -0,0 +1,20 @@
+node_modules
+package-lock.json
+yarn.lock
+
+.DS_Store
+.cache
+.env
+.vercel
+.output
+.nitro
+/build/
+/api/
+/server/build
+/public/build# Sentry Config File
+.env.sentry-build-plugin
+/test-results/
+/playwright-report/
+/blob-report/
+/playwright/.cache/
+.tanstack
\ No newline at end of file
diff --git a/examples/react/start-otel/.prettierignore b/examples/react/start-otel/.prettierignore
new file mode 100644
index 0000000000..2be5eaa6ec
--- /dev/null
+++ b/examples/react/start-otel/.prettierignore
@@ -0,0 +1,4 @@
+**/build
+**/public
+pnpm-lock.yaml
+routeTree.gen.ts
\ No newline at end of file
diff --git a/examples/react/start-otel/.vscode/settings.json b/examples/react/start-otel/.vscode/settings.json
new file mode 100644
index 0000000000..00b5278e58
--- /dev/null
+++ b/examples/react/start-otel/.vscode/settings.json
@@ -0,0 +1,11 @@
+{
+  "files.watcherExclude": {
+    "**/routeTree.gen.ts": true
+  },
+  "search.exclude": {
+    "**/routeTree.gen.ts": true
+  },
+  "files.readonlyInclude": {
+    "**/routeTree.gen.ts": true
+  }
+}
diff --git a/examples/react/start-otel/README.md b/examples/react/start-otel/README.md
new file mode 100644
index 0000000000..90cba4aac1
--- /dev/null
+++ b/examples/react/start-otel/README.md
@@ -0,0 +1,72 @@
+# Welcome to TanStack.com!
+
+This site is built with TanStack Router!
+
+- [TanStack Router Docs](https://tanstack.com/router)
+
+It's deployed automagically with Netlify!
+
+- [Netlify](https://netlify.com/)
+
+## Development
+
+From your terminal:
+
+```sh
+pnpm install
+pnpm dev
+```
+
+This starts your app in development mode, rebuilding assets on file changes.
+
+## Editing and previewing the docs of TanStack projects locally
+
+The documentations for all TanStack projects except for `React Charts` are hosted on [https://tanstack.com](https://tanstack.com), powered by this TanStack Router app.
+In production, the markdown doc pages are fetched from the GitHub repos of the projects, but in development they are read from the local file system.
+
+Follow these steps if you want to edit the doc pages of a project (in these steps we'll assume it's [`TanStack/form`](https://github.com/tanstack/form)) and preview them locally :
+
+1. Create a new directory called `tanstack`.
+
+```sh
+mkdir tanstack
+```
+
+2. Enter the directory and clone this repo and the repo of the project there.
+
+```sh
+cd tanstack
+git clone git@github.com:TanStack/tanstack.com.git
+git clone git@github.com:TanStack/form.git
+```
+
+> [!NOTE]
+> Your `tanstack` directory should look like this:
+>
+> ```
+> tanstack/
+>    |
+>    +-- form/
+>    |
+>    +-- tanstack.com/
+> ```
+
+> [!WARNING]
+> Make sure the name of the directory in your local file system matches the name of the project's repo. For example, `tanstack/form` must be cloned into `form` (this is the default) instead of `some-other-name`, because that way, the doc pages won't be found.
+
+3. Enter the `tanstack/tanstack.com` directory, install the dependencies and run the app in dev mode:
+
+```sh
+cd tanstack.com
+pnpm i
+# The app will run on https://localhost:3000 by default
+pnpm dev
+```
+
+4. Now you can visit http://localhost:3000/form/latest/docs/overview in the browser and see the changes you make in `tanstack/form/docs`.
+
+> [!NOTE]
+> The updated pages need to be manually reloaded in the browser.
+
+> [!WARNING]
+> You will need to update the `docs/config.json` file (in the project's repo) if you add a new doc page!
diff --git a/examples/react/start-otel/docker-compose.yml b/examples/react/start-otel/docker-compose.yml
new file mode 100644
index 0000000000..81340cd3d4
--- /dev/null
+++ b/examples/react/start-otel/docker-compose.yml
@@ -0,0 +1,14 @@
+version: "3.9"
+services:
+  jaeger:
+    image: jaegertracing/all-in-one:1.57
+    container_name: jaeger
+    environment:
+      - COLLECTOR_OTLP_ENABLED=true
+    ports:
+      - "16686:16686" # Jaeger UI
+      - "4317:4317"   # OTLP gRPC
+      - "4318:4318"   # OTLP HTTP (used by app)
+    restart: unless-stopped
+
+
diff --git a/examples/react/start-otel/package.json b/examples/react/start-otel/package.json
new file mode 100644
index 0000000000..de930ac5ab
--- /dev/null
+++ b/examples/react/start-otel/package.json
@@ -0,0 +1,36 @@
+{
+  "name": "tanstack-start-example-otel",
+  "private": true,
+  "sideEffects": false,
+  "type": "module",
+  "scripts": {
+    "dev": "vite dev",
+    "build": "vite build && tsc --noEmit",
+    "start": "node .output/server/index.mjs"
+  },
+  "dependencies": {
+    "@opentelemetry/api": "^1.9.0",
+    "@opentelemetry/exporter-trace-otlp-proto": "^0.206.0",
+    "@opentelemetry/sdk-node": "^0.206.0",
+    "@opentelemetry/sdk-trace-node": "^2.1.0",
+    "@tanstack/react-router": "^1.133.15",
+    "@tanstack/react-router-devtools": "^1.133.15",
+    "@tanstack/react-start": "^1.133.15",
+    "react": "^19.0.0",
+    "react-dom": "^19.0.0",
+    "tailwind-merge": "^2.6.0",
+    "zod": "^3.24.2"
+  },
+  "devDependencies": {
+    "@types/node": "^22.5.4",
+    "@types/react": "^19.0.8",
+    "@types/react-dom": "^19.0.3",
+    "@vitejs/plugin-react": "^4.6.0",
+    "autoprefixer": "^10.4.20",
+    "postcss": "^8.5.1",
+    "tailwindcss": "^3.4.17",
+    "typescript": "^5.7.2",
+    "vite": "^7.1.7",
+    "vite-tsconfig-paths": "^5.1.4"
+  }
+}
diff --git a/examples/react/start-otel/postcss.config.mjs b/examples/react/start-otel/postcss.config.mjs
new file mode 100644
index 0000000000..2e7af2b7f1
--- /dev/null
+++ b/examples/react/start-otel/postcss.config.mjs
@@ -0,0 +1,6 @@
+export default {
+  plugins: {
+    tailwindcss: {},
+    autoprefixer: {},
+  },
+}
diff --git a/examples/react/start-otel/public/android-chrome-192x192.png b/examples/react/start-otel/public/android-chrome-192x192.png
new file mode 100644
index 0000000000000000000000000000000000000000..09c8324f8c6781bc90fcf5dd38e0702bd5f171f3
GIT binary patch
diff --git a/examples/react/start-otel/public/android-chrome-512x512.png b/examples/react/start-otel/public/android-chrome-512x512.png
new file mode 100644
index 0000000000000000000000000000000000000000..11d626ea3d00fddd52861bf0af5554a92fc30d69
GIT binary patch
diff --git a/examples/react/start-otel/public/apple-touch-icon.png b/examples/react/start-otel/public/apple-touch-icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..5a9423cc02c40ea066d2a061cdcdf621c0718cb1
GIT binary patch
diff --git a/examples/react/start-otel/public/favicon-16x16.png b/examples/react/start-otel/public/favicon-16x16.png
new file mode 100644
index 0000000000000000000000000000000000000000..e3389b00443d602a249b48ae0e21e333971c9c1e
GIT binary patch
diff --git a/examples/react/start-otel/public/favicon-32x32.png b/examples/react/start-otel/public/favicon-32x32.png
new file mode 100644
index 0000000000000000000000000000000000000000..900c77d444c9b31e6144b6ac0bb1ab7bb7ca767f
GIT binary patch
diff --git a/examples/react/start-otel/public/favicon.ico b/examples/react/start-otel/public/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..1a1751676f7e22811b1070572093996c93c87617
GIT binary patch
diff --git a/examples/react/start-otel/public/favicon.png b/examples/react/start-otel/public/favicon.png
new file mode 100644
index 0000000000000000000000000000000000000000..1e77bc06091ade4496525a09d8900675afcf03f0
GIT binary patch
diff --git a/examples/react/start-otel/public/site.webmanifest b/examples/react/start-otel/public/site.webmanifest
new file mode 100644
index 0000000000..fa99de77db
--- /dev/null
+++ b/examples/react/start-otel/public/site.webmanifest
@@ -0,0 +1,19 @@
+{
+  "name": "",
+  "short_name": "",
+  "icons": [
+    {
+      "src": "/android-chrome-192x192.png",
+      "sizes": "192x192",
+      "type": "image/png"
+    },
+    {
+      "src": "/android-chrome-512x512.png",
+      "sizes": "512x512",
+      "type": "image/png"
+    }
+  ],
+  "theme_color": "#ffffff",
+  "background_color": "#ffffff",
+  "display": "standalone"
+}
diff --git a/examples/react/start-otel/src/components/DefaultCatchBoundary.tsx b/examples/react/start-otel/src/components/DefaultCatchBoundary.tsx
new file mode 100644
index 0000000000..f750e7bd2b
--- /dev/null
+++ b/examples/react/start-otel/src/components/DefaultCatchBoundary.tsx
@@ -0,0 +1,53 @@
+import {
+  ErrorComponent,
+  Link,
+  rootRouteId,
+  useMatch,
+  useRouter,
+} from '@tanstack/react-router'
+import type { ErrorComponentProps } from '@tanstack/react-router'
+
+export function DefaultCatchBoundary({ error }: ErrorComponentProps) {
+  const router = useRouter()
+  const isRoot = useMatch({
+    strict: false,
+    select: (state) => state.id === rootRouteId,
+  })
+
+  console.error('DefaultCatchBoundary Error:', error)
+
+  return (
+    <div className="min-w-0 flex-1 p-4 flex flex-col items-center justify-center gap-6">
+      <ErrorComponent error={error} />
+      <div className="flex gap-2 items-center flex-wrap">
+        <button
+          onClick={() => {
+            router.invalidate()
+          }}
+          className={`px-2 py-1 bg-gray-600 dark:bg-gray-700 rounded text-white uppercase font-extrabold`}
+        >
+          Try Again
+        </button>
+        {isRoot ? (
+          <Link
+            to="/"
+            className={`px-2 py-1 bg-gray-600 dark:bg-gray-700 rounded text-white uppercase font-extrabold`}
+          >
+            Home
+          </Link>
+        ) : (
+          <Link
+            to="/"
+            className={`px-2 py-1 bg-gray-600 dark:bg-gray-700 rounded text-white uppercase font-extrabold`}
+            onClick={(e) => {
+              e.preventDefault()
+              window.history.back()
+            }}
+          >
+            Go Back
+          </Link>
+        )}
+      </div>
+    </div>
+  )
+}
diff --git a/examples/react/start-otel/src/components/NotFound.tsx b/examples/react/start-otel/src/components/NotFound.tsx
new file mode 100644
index 0000000000..7b54fa5680
--- /dev/null
+++ b/examples/react/start-otel/src/components/NotFound.tsx
@@ -0,0 +1,25 @@
+import { Link } from '@tanstack/react-router'
+
+export function NotFound({ children }: { children?: any }) {
+  return (
+    <div className="space-y-2 p-2">
+      <div className="text-gray-600 dark:text-gray-400">
+        {children || <p>The page you are looking for does not exist.</p>}
+      </div>
+      <p className="flex items-center gap-2 flex-wrap">
+        <button
+          onClick={() => window.history.back()}
+          className="bg-emerald-500 text-white px-2 py-1 rounded uppercase font-black text-sm"
+        >
+          Go back
+        </button>
+        <Link
+          to="/"
+          className="bg-cyan-600 text-white px-2 py-1 rounded uppercase font-black text-sm"
+        >
+          Start Over
+        </Link>
+      </p>
+    </div>
+  )
+}
diff --git a/examples/react/start-otel/src/components/PostError.tsx b/examples/react/start-otel/src/components/PostError.tsx
new file mode 100644
index 0000000000..271f2d1de1
--- /dev/null
+++ b/examples/react/start-otel/src/components/PostError.tsx
@@ -0,0 +1,6 @@
+import { ErrorComponent } from '@tanstack/react-router'
+import type { ErrorComponentProps } from '@tanstack/react-router'
+
+export function PostErrorComponent({ error }: ErrorComponentProps) {
+  return <ErrorComponent error={error} />
+}
diff --git a/examples/react/start-otel/src/components/UserError.tsx b/examples/react/start-otel/src/components/UserError.tsx
new file mode 100644
index 0000000000..af5d0c6f16
--- /dev/null
+++ b/examples/react/start-otel/src/components/UserError.tsx
@@ -0,0 +1,6 @@
+import { ErrorComponent } from '@tanstack/react-router'
+import type { ErrorComponentProps } from '@tanstack/react-router'
+
+export function UserErrorComponent({ error }: ErrorComponentProps) {
+  return <ErrorComponent error={error} />
+}
diff --git a/examples/react/start-otel/src/otel.ts b/examples/react/start-otel/src/otel.ts
new file mode 100644
index 0000000000..f3bf76743d
--- /dev/null
+++ b/examples/react/start-otel/src/otel.ts
@@ -0,0 +1,16 @@
+import { NodeSDK } from '@opentelemetry/sdk-node'
+import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'
+import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'
+
+const sdk = new NodeSDK({
+  serviceName: 'tanstack-start',
+  spanProcessors: [
+    new SimpleSpanProcessor(
+      new OTLPTraceExporter({
+        url: 'http://localhost:4318/v1/traces',
+      }),
+    ),
+  ],
+})
+
+sdk.start()
diff --git a/examples/react/start-otel/src/routeTree.gen.ts b/examples/react/start-otel/src/routeTree.gen.ts
new file mode 100644
index 0000000000..06a64190d7
--- /dev/null
+++ b/examples/react/start-otel/src/routeTree.gen.ts
@@ -0,0 +1,447 @@
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file was automatically generated by TanStack Router.
+// You should NOT make any changes in this file as it will be overwritten.
+// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
+
+import { Route as rootRouteImport } from './routes/__root'
+import { Route as UsersRouteImport } from './routes/users'
+import { Route as RedirectRouteImport } from './routes/redirect'
+import { Route as PostsRouteImport } from './routes/posts'
+import { Route as DeferredRouteImport } from './routes/deferred'
+import { Route as CustomScriptDotjsRouteImport } from './routes/customScript[.]js'
+import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout'
+import { Route as IndexRouteImport } from './routes/index'
+import { Route as UsersIndexRouteImport } from './routes/users.index'
+import { Route as PostsIndexRouteImport } from './routes/posts.index'
+import { Route as UsersUserIdRouteImport } from './routes/users.$userId'
+import { Route as PostsPostIdRouteImport } from './routes/posts.$postId'
+import { Route as ApiUsersRouteImport } from './routes/api/users'
+import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout'
+import { Route as PostsPostIdDeepRouteImport } from './routes/posts_.$postId.deep'
+import { Route as ApiUsersUserIdRouteImport } from './routes/api/users.$userId'
+import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b'
+import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a'
+
+const UsersRoute = UsersRouteImport.update({
+  id: '/users',
+  path: '/users',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const RedirectRoute = RedirectRouteImport.update({
+  id: '/redirect',
+  path: '/redirect',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const PostsRoute = PostsRouteImport.update({
+  id: '/posts',
+  path: '/posts',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const DeferredRoute = DeferredRouteImport.update({
+  id: '/deferred',
+  path: '/deferred',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const CustomScriptDotjsRoute = CustomScriptDotjsRouteImport.update({
+  id: '/customScript.js',
+  path: '/customScript.js',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const PathlessLayoutRoute = PathlessLayoutRouteImport.update({
+  id: '/_pathlessLayout',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const IndexRoute = IndexRouteImport.update({
+  id: '/',
+  path: '/',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const UsersIndexRoute = UsersIndexRouteImport.update({
+  id: '/',
+  path: '/',
+  getParentRoute: () => UsersRoute,
+} as any)
+const PostsIndexRoute = PostsIndexRouteImport.update({
+  id: '/',
+  path: '/',
+  getParentRoute: () => PostsRoute,
+} as any)
+const UsersUserIdRoute = UsersUserIdRouteImport.update({
+  id: '/$userId',
+  path: '/$userId',
+  getParentRoute: () => UsersRoute,
+} as any)
+const PostsPostIdRoute = PostsPostIdRouteImport.update({
+  id: '/$postId',
+  path: '/$postId',
+  getParentRoute: () => PostsRoute,
+} as any)
+const ApiUsersRoute = ApiUsersRouteImport.update({
+  id: '/api/users',
+  path: '/api/users',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const PathlessLayoutNestedLayoutRoute =
+  PathlessLayoutNestedLayoutRouteImport.update({
+    id: '/_nested-layout',
+    getParentRoute: () => PathlessLayoutRoute,
+  } as any)
+const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({
+  id: '/posts_/$postId/deep',
+  path: '/posts/$postId/deep',
+  getParentRoute: () => rootRouteImport,
+} as any)
+const ApiUsersUserIdRoute = ApiUsersUserIdRouteImport.update({
+  id: '/$userId',
+  path: '/$userId',
+  getParentRoute: () => ApiUsersRoute,
+} as any)
+const PathlessLayoutNestedLayoutRouteBRoute =
+  PathlessLayoutNestedLayoutRouteBRouteImport.update({
+    id: '/route-b',
+    path: '/route-b',
+    getParentRoute: () => PathlessLayoutNestedLayoutRoute,
+  } as any)
+const PathlessLayoutNestedLayoutRouteARoute =
+  PathlessLayoutNestedLayoutRouteARouteImport.update({
+    id: '/route-a',
+    path: '/route-a',
+    getParentRoute: () => PathlessLayoutNestedLayoutRoute,
+  } as any)
+
+export interface FileRoutesByFullPath {
+  '/': typeof IndexRoute
+  '/customScript.js': typeof CustomScriptDotjsRoute
+  '/deferred': typeof DeferredRoute
+  '/posts': typeof PostsRouteWithChildren
+  '/redirect': typeof RedirectRoute
+  '/users': typeof UsersRouteWithChildren
+  '/api/users': typeof ApiUsersRouteWithChildren
+  '/posts/$postId': typeof PostsPostIdRoute
+  '/users/$userId': typeof UsersUserIdRoute
+  '/posts/': typeof PostsIndexRoute
+  '/users/': typeof UsersIndexRoute
+  '/route-a': typeof PathlessLayoutNestedLayoutRouteARoute
+  '/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute
+  '/api/users/$userId': typeof ApiUsersUserIdRoute
+  '/posts/$postId/deep': typeof PostsPostIdDeepRoute
+}
+export interface FileRoutesByTo {
+  '/': typeof IndexRoute
+  '/customScript.js': typeof CustomScriptDotjsRoute
+  '/deferred': typeof DeferredRoute
+  '/redirect': typeof RedirectRoute
+  '/api/users': typeof ApiUsersRouteWithChildren
+  '/posts/$postId': typeof PostsPostIdRoute
+  '/users/$userId': typeof UsersUserIdRoute
+  '/posts': typeof PostsIndexRoute
+  '/users': typeof UsersIndexRoute
+  '/route-a': typeof PathlessLayoutNestedLayoutRouteARoute
+  '/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute
+  '/api/users/$userId': typeof ApiUsersUserIdRoute
+  '/posts/$postId/deep': typeof PostsPostIdDeepRoute
+}
+export interface FileRoutesById {
+  __root__: typeof rootRouteImport
+  '/': typeof IndexRoute
+  '/_pathlessLayout': typeof PathlessLayoutRouteWithChildren
+  '/customScript.js': typeof CustomScriptDotjsRoute
+  '/deferred': typeof DeferredRoute
+  '/posts': typeof PostsRouteWithChildren
+  '/redirect': typeof RedirectRoute
+  '/users': typeof UsersRouteWithChildren
+  '/_pathlessLayout/_nested-layout': typeof PathlessLayoutNestedLayoutRouteWithChildren
+  '/api/users': typeof ApiUsersRouteWithChildren
+  '/posts/$postId': typeof PostsPostIdRoute
+  '/users/$userId': typeof UsersUserIdRoute
+  '/posts/': typeof PostsIndexRoute
+  '/users/': typeof UsersIndexRoute
+  '/_pathlessLayout/_nested-layout/route-a': typeof PathlessLayoutNestedLayoutRouteARoute
+  '/_pathlessLayout/_nested-layout/route-b': typeof PathlessLayoutNestedLayoutRouteBRoute
+  '/api/users/$userId': typeof ApiUsersUserIdRoute
+  '/posts_/$postId/deep': typeof PostsPostIdDeepRoute
+}
+export interface FileRouteTypes {
+  fileRoutesByFullPath: FileRoutesByFullPath
+  fullPaths:
+    | '/'
+    | '/customScript.js'
+    | '/deferred'
+    | '/posts'
+    | '/redirect'
+    | '/users'
+    | '/api/users'
+    | '/posts/$postId'
+    | '/users/$userId'
+    | '/posts/'
+    | '/users/'
+    | '/route-a'
+    | '/route-b'
+    | '/api/users/$userId'
+    | '/posts/$postId/deep'
+  fileRoutesByTo: FileRoutesByTo
+  to:
+    | '/'
+    | '/customScript.js'
+    | '/deferred'
+    | '/redirect'
+    | '/api/users'
+    | '/posts/$postId'
+    | '/users/$userId'
+    | '/posts'
+    | '/users'
+    | '/route-a'
+    | '/route-b'
+    | '/api/users/$userId'
+    | '/posts/$postId/deep'
+  id:
+    | '__root__'
+    | '/'
+    | '/_pathlessLayout'
+    | '/customScript.js'
+    | '/deferred'
+    | '/posts'
+    | '/redirect'
+    | '/users'
+    | '/_pathlessLayout/_nested-layout'
+    | '/api/users'
+    | '/posts/$postId'
+    | '/users/$userId'
+    | '/posts/'
+    | '/users/'
+    | '/_pathlessLayout/_nested-layout/route-a'
+    | '/_pathlessLayout/_nested-layout/route-b'
+    | '/api/users/$userId'
+    | '/posts_/$postId/deep'
+  fileRoutesById: FileRoutesById
+}
+export interface RootRouteChildren {
+  IndexRoute: typeof IndexRoute
+  PathlessLayoutRoute: typeof PathlessLayoutRouteWithChildren
+  CustomScriptDotjsRoute: typeof CustomScriptDotjsRoute
+  DeferredRoute: typeof DeferredRoute
+  PostsRoute: typeof PostsRouteWithChildren
+  RedirectRoute: typeof RedirectRoute
+  UsersRoute: typeof UsersRouteWithChildren
+  ApiUsersRoute: typeof ApiUsersRouteWithChildren
+  PostsPostIdDeepRoute: typeof PostsPostIdDeepRoute
+}
+
+declare module '@tanstack/react-router' {
+  interface FileRoutesByPath {
+    '/users': {
+      id: '/users'
+      path: '/users'
+      fullPath: '/users'
+      preLoaderRoute: typeof UsersRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/redirect': {
+      id: '/redirect'
+      path: '/redirect'
+      fullPath: '/redirect'
+      preLoaderRoute: typeof RedirectRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/posts': {
+      id: '/posts'
+      path: '/posts'
+      fullPath: '/posts'
+      preLoaderRoute: typeof PostsRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/deferred': {
+      id: '/deferred'
+      path: '/deferred'
+      fullPath: '/deferred'
+      preLoaderRoute: typeof DeferredRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/customScript.js': {
+      id: '/customScript.js'
+      path: '/customScript.js'
+      fullPath: '/customScript.js'
+      preLoaderRoute: typeof CustomScriptDotjsRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/_pathlessLayout': {
+      id: '/_pathlessLayout'
+      path: ''
+      fullPath: ''
+      preLoaderRoute: typeof PathlessLayoutRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/': {
+      id: '/'
+      path: '/'
+      fullPath: '/'
+      preLoaderRoute: typeof IndexRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/users/': {
+      id: '/users/'
+      path: '/'
+      fullPath: '/users/'
+      preLoaderRoute: typeof UsersIndexRouteImport
+      parentRoute: typeof UsersRoute
+    }
+    '/posts/': {
+      id: '/posts/'
+      path: '/'
+      fullPath: '/posts/'
+      preLoaderRoute: typeof PostsIndexRouteImport
+      parentRoute: typeof PostsRoute
+    }
+    '/users/$userId': {
+      id: '/users/$userId'
+      path: '/$userId'
+      fullPath: '/users/$userId'
+      preLoaderRoute: typeof UsersUserIdRouteImport
+      parentRoute: typeof UsersRoute
+    }
+    '/posts/$postId': {
+      id: '/posts/$postId'
+      path: '/$postId'
+      fullPath: '/posts/$postId'
+      preLoaderRoute: typeof PostsPostIdRouteImport
+      parentRoute: typeof PostsRoute
+    }
+    '/api/users': {
+      id: '/api/users'
+      path: '/api/users'
+      fullPath: '/api/users'
+      preLoaderRoute: typeof ApiUsersRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/_pathlessLayout/_nested-layout': {
+      id: '/_pathlessLayout/_nested-layout'
+      path: ''
+      fullPath: ''
+      preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport
+      parentRoute: typeof PathlessLayoutRoute
+    }
+    '/posts_/$postId/deep': {
+      id: '/posts_/$postId/deep'
+      path: '/posts/$postId/deep'
+      fullPath: '/posts/$postId/deep'
+      preLoaderRoute: typeof PostsPostIdDeepRouteImport
+      parentRoute: typeof rootRouteImport
+    }
+    '/api/users/$userId': {
+      id: '/api/users/$userId'
+      path: '/$userId'
+      fullPath: '/api/users/$userId'
+      preLoaderRoute: typeof ApiUsersUserIdRouteImport
+      parentRoute: typeof ApiUsersRoute
+    }
+    '/_pathlessLayout/_nested-layout/route-b': {
+      id: '/_pathlessLayout/_nested-layout/route-b'
+      path: '/route-b'
+      fullPath: '/route-b'
+      preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport
+      parentRoute: typeof PathlessLayoutNestedLayoutRoute
+    }
+    '/_pathlessLayout/_nested-layout/route-a': {
+      id: '/_pathlessLayout/_nested-layout/route-a'
+      path: '/route-a'
+      fullPath: '/route-a'
+      preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport
+      parentRoute: typeof PathlessLayoutNestedLayoutRoute
+    }
+  }
+}
+
+interface PathlessLayoutNestedLayoutRouteChildren {
+  PathlessLayoutNestedLayoutRouteARoute: typeof PathlessLayoutNestedLayoutRouteARoute
+  PathlessLayoutNestedLayoutRouteBRoute: typeof PathlessLayoutNestedLayoutRouteBRoute
+}
+
+const PathlessLayoutNestedLayoutRouteChildren: PathlessLayoutNestedLayoutRouteChildren =
+  {
+    PathlessLayoutNestedLayoutRouteARoute:
+      PathlessLayoutNestedLayoutRouteARoute,
+    PathlessLayoutNestedLayoutRouteBRoute:
+      PathlessLayoutNestedLayoutRouteBRoute,
+  }
+
+const PathlessLayoutNestedLayoutRouteWithChildren =
+  PathlessLayoutNestedLayoutRoute._addFileChildren(
+    PathlessLayoutNestedLayoutRouteChildren,
+  )
+
+interface PathlessLayoutRouteChildren {
+  PathlessLayoutNestedLayoutRoute: typeof PathlessLayoutNestedLayoutRouteWithChildren
+}
+
+const PathlessLayoutRouteChildren: PathlessLayoutRouteChildren = {
+  PathlessLayoutNestedLayoutRoute: PathlessLayoutNestedLayoutRouteWithChildren,
+}
+
+const PathlessLayoutRouteWithChildren = PathlessLayoutRoute._addFileChildren(
+  PathlessLayoutRouteChildren,
+)
+
+interface PostsRouteChildren {
+  PostsPostIdRoute: typeof PostsPostIdRoute
+  PostsIndexRoute: typeof PostsIndexRoute
+}
+
+const PostsRouteChildren: PostsRouteChildren = {
+  PostsPostIdRoute: PostsPostIdRoute,
+  PostsIndexRoute: PostsIndexRoute,
+}
+
+const PostsRouteWithChildren = PostsRoute._addFileChildren(PostsRouteChildren)
+
+interface UsersRouteChildren {
+  UsersUserIdRoute: typeof UsersUserIdRoute
+  UsersIndexRoute: typeof UsersIndexRoute
+}
+
+const UsersRouteChildren: UsersRouteChildren = {
+  UsersUserIdRoute: UsersUserIdRoute,
+  UsersIndexRoute: UsersIndexRoute,
+}
+
+const UsersRouteWithChildren = UsersRoute._addFileChildren(UsersRouteChildren)
+
+interface ApiUsersRouteChildren {
+  ApiUsersUserIdRoute: typeof ApiUsersUserIdRoute
+}
+
+const ApiUsersRouteChildren: ApiUsersRouteChildren = {
+  ApiUsersUserIdRoute: ApiUsersUserIdRoute,
+}
+
+const ApiUsersRouteWithChildren = ApiUsersRoute._addFileChildren(
+  ApiUsersRouteChildren,
+)
+
+const rootRouteChildren: RootRouteChildren = {
+  IndexRoute: IndexRoute,
+  PathlessLayoutRoute: PathlessLayoutRouteWithChildren,
+  CustomScriptDotjsRoute: CustomScriptDotjsRoute,
+  DeferredRoute: DeferredRoute,
+  PostsRoute: PostsRouteWithChildren,
+  RedirectRoute: RedirectRoute,
+  UsersRoute: UsersRouteWithChildren,
+  ApiUsersRoute: ApiUsersRouteWithChildren,
+  PostsPostIdDeepRoute: PostsPostIdDeepRoute,
+}
+export const routeTree = rootRouteImport
+  ._addFileChildren(rootRouteChildren)
+  ._addFileTypes<FileRouteTypes>()
+
+import type { getRouter } from './router.tsx'
+import type { createStart } from '@tanstack/react-start'
+declare module '@tanstack/react-start' {
+  interface Register {
+    ssr: true
+    router: Awaited<ReturnType<typeof getRouter>>
+  }
+}
diff --git a/examples/react/start-otel/src/router.tsx b/examples/react/start-otel/src/router.tsx
new file mode 100644
index 0000000000..f380f73be7
--- /dev/null
+++ b/examples/react/start-otel/src/router.tsx
@@ -0,0 +1,15 @@
+import { createRouter } from '@tanstack/react-router'
+import { routeTree } from './routeTree.gen'
+import { DefaultCatchBoundary } from './components/DefaultCatchBoundary'
+import { NotFound } from './components/NotFound'
+
+export function getRouter() {
+  const router = createRouter({
+    routeTree,
+    defaultPreload: 'intent',
+    defaultErrorComponent: DefaultCatchBoundary,
+    defaultNotFoundComponent: () => <NotFound />,
+    scrollRestoration: true,
+  })
+  return router
+}
diff --git a/examples/react/start-otel/src/routes/__root.tsx b/examples/react/start-otel/src/routes/__root.tsx
new file mode 100644
index 0000000000..346409e9d9
--- /dev/null
+++ b/examples/react/start-otel/src/routes/__root.tsx
@@ -0,0 +1,131 @@
+/// <reference types="vite/client" />
+import {
+  HeadContent,
+  Link,
+  Scripts,
+  createRootRoute,
+} from '@tanstack/react-router'
+import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
+import * as React from 'react'
+import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
+import { NotFound } from '~/components/NotFound'
+import appCss from '~/styles/app.css?url'
+import { seo } from '~/utils/seo'
+
+export const Route = createRootRoute({
+  head: () => ({
+    meta: [
+      {
+        charSet: 'utf-8',
+      },
+      {
+        name: 'viewport',
+        content: 'width=device-width, initial-scale=1',
+      },
+      ...seo({
+        title:
+          'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
+        description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
+      }),
+    ],
+    links: [
+      { rel: 'stylesheet', href: appCss },
+      {
+        rel: 'apple-touch-icon',
+        sizes: '180x180',
+        href: '/apple-touch-icon.png',
+      },
+      {
+        rel: 'icon',
+        type: 'image/png',
+        sizes: '32x32',
+        href: '/favicon-32x32.png',
+      },
+      {
+        rel: 'icon',
+        type: 'image/png',
+        sizes: '16x16',
+        href: '/favicon-16x16.png',
+      },
+      { rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
+      { rel: 'icon', href: '/favicon.ico' },
+    ],
+    scripts: [
+      {
+        src: '/customScript.js',
+        type: 'text/javascript',
+      },
+    ],
+  }),
+  errorComponent: DefaultCatchBoundary,
+  notFoundComponent: () => <NotFound />,
+  shellComponent: RootDocument,
+})
+
+function RootDocument({ children }: { children: React.ReactNode }) {
+  return (
+    <html>
+      <head>
+        <HeadContent />
+      </head>
+      <body>
+        <div className="p-2 flex gap-2 text-lg">
+          <Link
+            to="/"
+            activeProps={{
+              className: 'font-bold',
+            }}
+            activeOptions={{ exact: true }}
+          >
+            Home
+          </Link>{' '}
+          <Link
+            to="/posts"
+            activeProps={{
+              className: 'font-bold',
+            }}
+          >
+            Posts
+          </Link>{' '}
+          <Link
+            to="/users"
+            activeProps={{
+              className: 'font-bold',
+            }}
+          >
+            Users
+          </Link>{' '}
+          <Link
+            to="/route-a"
+            activeProps={{
+              className: 'font-bold',
+            }}
+          >
+            Pathless Layout
+          </Link>{' '}
+          <Link
+            to="/deferred"
+            activeProps={{
+              className: 'font-bold',
+            }}
+          >
+            Deferred
+          </Link>{' '}
+          <Link
+            // @ts-expect-error
+            to="/this-route-does-not-exist"
+            activeProps={{
+              className: 'font-bold',
+            }}
+          >
+            This Route Does Not Exist
+          </Link>
+        </div>
+        <hr />
+        {children}
+        <TanStackRouterDevtools position="bottom-right" />
+        <Scripts />
+      </body>
+    </html>
+  )
+}
diff --git a/examples/react/start-otel/src/routes/_pathlessLayout.tsx b/examples/react/start-otel/src/routes/_pathlessLayout.tsx
new file mode 100644
index 0000000000..c3b12442b8
--- /dev/null
+++ b/examples/react/start-otel/src/routes/_pathlessLayout.tsx
@@ -0,0 +1,16 @@
+import { Outlet, createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_pathlessLayout')({
+  component: LayoutComponent,
+})
+
+function LayoutComponent() {
+  return (
+    <div className="p-2">
+      <div className="border-b">I'm a layout</div>
+      <div>
+        <Outlet />
+      </div>
+    </div>
+  )
+}
diff --git a/examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout.tsx b/examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout.tsx
new file mode 100644
index 0000000000..9a48b73a46
--- /dev/null
+++ b/examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout.tsx
@@ -0,0 +1,34 @@
+import { Link, Outlet, createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({
+  component: LayoutComponent,
+})
+
+function LayoutComponent() {
+  return (
+    <div>
+      <div>I'm a nested layout</div>
+      <div className="flex gap-2 border-b">
+        <Link
+          to="/route-a"
+          activeProps={{
+            className: 'font-bold',
+          }}
+        >
+          Go to route A
+        </Link>
+        <Link
+          to="/route-b"
+          activeProps={{
+            className: 'font-bold',
+          }}
+        >
+          Go to route B
+        </Link>
+      </div>
+      <div>
+        <Outlet />
+      </div>
+    </div>
+  )
+}
diff --git a/examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-a.tsx
new file mode 100644
index 0000000000..426a8fe486
--- /dev/null
+++ b/examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-a.tsx
@@ -0,0 +1,11 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')(
+  {
+    component: LayoutAComponent,
+  },
+)
+
+function LayoutAComponent() {
+  return <div>I'm A!</div>
+}
diff --git a/examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-b.tsx
new file mode 100644
index 0000000000..20facf2daf
--- /dev/null
+++ b/examples/react/start-otel/src/routes/_pathlessLayout/_nested-layout/route-b.tsx
@@ -0,0 +1,11 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')(
+  {
+    component: LayoutBComponent,
+  },
+)
+
+function LayoutBComponent() {
+  return <div>I'm B!</div>
+}
diff --git a/examples/react/start-otel/src/routes/api/users.$userId.ts b/examples/react/start-otel/src/routes/api/users.$userId.ts
new file mode 100644
index 0000000000..2ae7eb9c04
--- /dev/null
+++ b/examples/react/start-otel/src/routes/api/users.$userId.ts
@@ -0,0 +1,32 @@
+import { createFileRoute } from '@tanstack/react-router'
+import { json } from '@tanstack/react-start'
+import type { User } from '~/utils/users'
+
+export const Route = createFileRoute('/api/users/$userId')({
+  server: {
+    handlers: {
+      GET: async ({ params, request }) => {
+        console.info(`Fetching users by id=${params.userId}... @`, request.url)
+        try {
+          const res = await fetch(
+            'https://jsonplaceholder.typicode.com/users/' + params.userId,
+          )
+          if (!res.ok) {
+            throw new Error('Failed to fetch user')
+          }
+
+          const user = (await res.json()) as User
+
+          return json({
+            id: user.id,
+            name: user.name,
+            email: user.email,
+          })
+        } catch (e) {
+          console.error(e)
+          return json({ error: 'User not found' }, { status: 404 })
+        }
+      },
+    },
+  },
+})
diff --git a/examples/react/start-otel/src/routes/api/users.ts b/examples/react/start-otel/src/routes/api/users.ts
new file mode 100644
index 0000000000..c1e7473b0c
--- /dev/null
+++ b/examples/react/start-otel/src/routes/api/users.ts
@@ -0,0 +1,63 @@
+import { createFileRoute } from '@tanstack/react-router'
+import { getRequestHeaders } from '@tanstack/react-start/server'
+import { createMiddleware, json } from '@tanstack/react-start'
+import type { User } from '~/utils/users'
+
+const userLoggerMiddleware = createMiddleware().server(async ({ next }) => {
+  console.info('In: /users')
+  console.info('Request Headers:', getRequestHeaders())
+  const result = await next()
+  result.response.headers.set('x-users', 'true')
+  console.info('Out: /users')
+  return result
+})
+
+const testParentMiddleware = createMiddleware().server(async ({ next }) => {
+  console.info('In: testParentMiddleware')
+  const result = await next()
+  result.response.headers.set('x-test-parent', 'true')
+  console.info('Out: testParentMiddleware')
+  return result
+})
+
+const testMiddleware = createMiddleware()
+  .middleware([testParentMiddleware])
+  .server(async ({ next }) => {
+    console.info('In: testMiddleware')
+    const result = await next()
+    result.response.headers.set('x-test', 'true')
+
+    // if (Math.random() > 0.5) {
+    //   throw new Response(null, {
+    //     status: 302,
+    //     headers: { Location: 'https://www.google.com' },
+    //   })
+    // }
+
+    console.info('Out: testMiddleware')
+    return result
+  })
+
+export const Route = createFileRoute('/api/users')({
+  server: {
+    middleware: [testMiddleware, userLoggerMiddleware],
+    handlers: {
+      GET: async ({ request }) => {
+        console.info('GET /api/users @', request.url)
+        console.info('Fetching users... @', request.url)
+        const res = await fetch('https://jsonplaceholder.typicode.com/users')
+        if (!res.ok) {
+          throw new Error('Failed to fetch users')
+        }
+
+        const data = (await res.json()) as Array<User>
+
+        const list = data.slice(0, 10)
+
+        return json(
+          list.map((u) => ({ id: u.id, name: u.name, email: u.email })),
+        )
+      },
+    },
+  },
+})
diff --git a/examples/react/start-otel/src/routes/customScript[.]js.ts b/examples/react/start-otel/src/routes/customScript[.]js.ts
new file mode 100644
index 0000000000..811471ac15
--- /dev/null
+++ b/examples/react/start-otel/src/routes/customScript[.]js.ts
@@ -0,0 +1,15 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/customScript.js')({
+  server: {
+    handlers: {
+      GET: () => {
+        return new Response('console.log("Hello from customScript.js!")', {
+          headers: {
+            'Content-Type': 'application/javascript',
+          },
+        })
+      },
+    },
+  },
+})
diff --git a/examples/react/start-otel/src/routes/deferred.tsx b/examples/react/start-otel/src/routes/deferred.tsx
new file mode 100644
index 0000000000..c38808243e
--- /dev/null
+++ b/examples/react/start-otel/src/routes/deferred.tsx
@@ -0,0 +1,62 @@
+import { Await, createFileRoute } from '@tanstack/react-router'
+import { createServerFn } from '@tanstack/react-start'
+import { Suspense, useState } from 'react'
+
+const personServerFn = createServerFn({ method: 'GET' })
+  .inputValidator((d: string) => d)
+  .handler(({ data: name }) => {
+    return { name, randomNumber: Math.floor(Math.random() * 100) }
+  })
+
+const slowServerFn = createServerFn({ method: 'GET' })
+  .inputValidator((d: string) => d)
+  .handler(async ({ data: name }) => {
+    await new Promise((r) => setTimeout(r, 1000))
+    return { name, randomNumber: Math.floor(Math.random() * 100) }
+  })
+
+export const Route = createFileRoute('/deferred')({
+  loader: async () => {
+    return {
+      deferredStuff: new Promise<string>((r) =>
+        setTimeout(() => r('Hello deferred!'), 2000),
+      ),
+      deferredPerson: slowServerFn({ data: 'Tanner Linsley' }),
+      person: await personServerFn({ data: 'John Doe' }),
+    }
+  },
+  component: Deferred,
+})
+
+function Deferred() {
+  const [count, setCount] = useState(0)
+  const { deferredStuff, deferredPerson, person } = Route.useLoaderData()
+
+  return (
+    <div className="p-2">
+      <div data-testid="regular-person">
+        {person.name} - {person.randomNumber}
+      </div>
+      <Suspense fallback={<div>Loading person...</div>}>
+        <Await
+          promise={deferredPerson}
+          children={(data) => (
+            <div data-testid="deferred-person">
+              {data.name} - {data.randomNumber}
+            </div>
+          )}
+        />
+      </Suspense>
+      <Suspense fallback={<div>Loading stuff...</div>}>
+        <Await
+          promise={deferredStuff}
+          children={(data) => <h3 data-testid="deferred-stuff">{data}</h3>}
+        />
+      </Suspense>
+      <div>Count: {count}</div>
+      <div>
+        <button onClick={() => setCount(count + 1)}>Increment</button>
+      </div>
+    </div>
+  )
+}
diff --git a/examples/react/start-otel/src/routes/index.tsx b/examples/react/start-otel/src/routes/index.tsx
new file mode 100644
index 0000000000..09a907cb18
--- /dev/null
+++ b/examples/react/start-otel/src/routes/index.tsx
@@ -0,0 +1,13 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/')({
+  component: Home,
+})
+
+function Home() {
+  return (
+    <div className="p-2">
+      <h3>Welcome Home!!!</h3>
+    </div>
+  )
+}
diff --git a/examples/react/start-otel/src/routes/posts.$postId.tsx b/examples/react/start-otel/src/routes/posts.$postId.tsx
new file mode 100644
index 0000000000..65905bf8c4
--- /dev/null
+++ b/examples/react/start-otel/src/routes/posts.$postId.tsx
@@ -0,0 +1,34 @@
+import { Link, createFileRoute } from '@tanstack/react-router'
+import { fetchPost } from '../utils/posts'
+import { NotFound } from '~/components/NotFound'
+import { PostErrorComponent } from '~/components/PostError'
+
+export const Route = createFileRoute('/posts/$postId')({
+  loader: ({ params: { postId } }) => fetchPost({ data: postId }),
+  errorComponent: PostErrorComponent,
+  component: PostComponent,
+  notFoundComponent: () => {
+    return <NotFound>Post not found</NotFound>
+  },
+})
+
+function PostComponent() {
+  const post = Route.useLoaderData()
+
+  return (
+    <div className="space-y-2">
+      <h4 className="text-xl font-bold underline">{post.title}</h4>
+      <div className="text-sm">{post.body}</div>
+      <Link
+        to="/posts/$postId/deep"
+        params={{
+          postId: String(post.id),
+        }}
+        activeProps={{ className: 'text-black font-bold' }}
+        className="inline-block py-1 text-blue-800 hover:text-blue-600"
+      >
+        Deep View
+      </Link>
+    </div>
+  )
+}
diff --git a/examples/react/start-otel/src/routes/posts.index.tsx b/examples/react/start-otel/src/routes/posts.index.tsx
new file mode 100644
index 0000000000..5b5f08f95b
--- /dev/null
+++ b/examples/react/start-otel/src/routes/posts.index.tsx
@@ -0,0 +1,9 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/posts/')({
+  component: PostsIndexComponent,
+})
+
+function PostsIndexComponent() {
+  return <div>Select a post.</div>
+}
diff --git a/examples/react/start-otel/src/routes/posts.tsx b/examples/react/start-otel/src/routes/posts.tsx
new file mode 100644
index 0000000000..9b9162be7c
--- /dev/null
+++ b/examples/react/start-otel/src/routes/posts.tsx
@@ -0,0 +1,38 @@
+import { Link, Outlet, createFileRoute } from '@tanstack/react-router'
+import { fetchPosts } from '../utils/posts'
+
+export const Route = createFileRoute('/posts')({
+  loader: async () => fetchPosts(),
+  component: PostsComponent,
+})
+
+function PostsComponent() {
+  const posts = Route.useLoaderData()
+
+  return (
+    <div className="p-2 flex gap-2">
+      <ul className="list-disc pl-4">
+        {[...posts, { id: 'i-do-not-exist', title: 'Non-existent Post' }].map(
+          (post) => {
+            return (
+              <li key={post.id} className="whitespace-nowrap">
+                <Link
+                  to="/posts/$postId"
+                  params={{
+                    postId: String(post.id),
+                  }}
+                  className="block py-1 text-blue-800 hover:text-blue-600"
+                  activeProps={{ className: 'text-black font-bold' }}
+                >
+                  <div>{post.title.substring(0, 20)}</div>
+                </Link>
+              </li>
+            )
+          },
+        )}
+      </ul>
+      <hr />
+      <Outlet />
+    </div>
+  )
+}
diff --git a/examples/react/start-otel/src/routes/posts_.$postId.deep.tsx b/examples/react/start-otel/src/routes/posts_.$postId.deep.tsx
new file mode 100644
index 0000000000..29e6c39b5a
--- /dev/null
+++ b/examples/react/start-otel/src/routes/posts_.$postId.deep.tsx
@@ -0,0 +1,29 @@
+import { Link, createFileRoute } from '@tanstack/react-router'
+import { fetchPost } from '../utils/posts'
+import { PostErrorComponent } from '~/components/PostError'
+
+export const Route = createFileRoute('/posts_/$postId/deep')({
+  loader: async ({ params: { postId } }) =>
+    fetchPost({
+      data: postId,
+    }),
+  errorComponent: PostErrorComponent,
+  component: PostDeepComponent,
+})
+
+function PostDeepComponent() {
+  const post = Route.useLoaderData()
+
+  return (
+    <div className="p-2 space-y-2">
+      <Link
+        to="/posts"
+        className="block py-1 text-blue-800 hover:text-blue-600"
+      >
+        ← All Posts
+      </Link>
+      <h4 className="text-xl font-bold underline">{post.title}</h4>
+      <div className="text-sm">{post.body}</div>
+    </div>
+  )
+}
diff --git a/examples/react/start-otel/src/routes/redirect.tsx b/examples/react/start-otel/src/routes/redirect.tsx
new file mode 100644
index 0000000000..ea34b6e420
--- /dev/null
+++ b/examples/react/start-otel/src/routes/redirect.tsx
@@ -0,0 +1,9 @@
+import { createFileRoute, redirect } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/redirect')({
+  beforeLoad: () => {
+    throw redirect({
+      to: '/posts',
+    })
+  },
+})
diff --git a/examples/react/start-otel/src/routes/users.$userId.tsx b/examples/react/start-otel/src/routes/users.$userId.tsx
new file mode 100644
index 0000000000..1df768344d
--- /dev/null
+++ b/examples/react/start-otel/src/routes/users.$userId.tsx
@@ -0,0 +1,45 @@
+import { createFileRoute } from '@tanstack/react-router'
+import { NotFound } from 'src/components/NotFound'
+import { UserErrorComponent } from 'src/components/UserError'
+import type { User } from '../utils/users'
+
+export const Route = createFileRoute('/users/$userId')({
+  loader: async ({ params: { userId } }) => {
+    try {
+      const res = await fetch('/api/users/' + userId)
+      if (!res.ok) {
+        throw new Error('Unexpected status code')
+      }
+
+      const data = await res.json()
+
+      return data as User
+    } catch {
+      throw new Error('Failed to fetch user')
+    }
+  },
+  errorComponent: UserErrorComponent,
+  component: UserComponent,
+  notFoundComponent: () => {
+    return <NotFound>User not found</NotFound>
+  },
+})
+
+function UserComponent() {
+  const user = Route.useLoaderData()
+
+  return (
+    <div className="space-y-2">
+      <h4 className="text-xl font-bold underline">{user.name}</h4>
+      <div className="text-sm">{user.email}</div>
+      <div>
+        <a
+          href={`/api/users/${user.id}`}
+          className="text-blue-800 hover:text-blue-600 underline"
+        >
+          View as JSON
+        </a>
+      </div>
+    </div>
+  )
+}
diff --git a/examples/react/start-otel/src/routes/users.index.tsx b/examples/react/start-otel/src/routes/users.index.tsx
new file mode 100644
index 0000000000..27d136987e
--- /dev/null
+++ b/examples/react/start-otel/src/routes/users.index.tsx
@@ -0,0 +1,19 @@
+import { createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/users/')({
+  component: UsersIndexComponent,
+})
+
+function UsersIndexComponent() {
+  return (
+    <div>
+      Select a user or{' '}
+      <a
+        href="/api/users"
+        className="text-blue-800 hover:text-blue-600 underline"
+      >
+        view as JSON
+      </a>
+    </div>
+  )
+}
diff --git a/examples/react/start-otel/src/routes/users.tsx b/examples/react/start-otel/src/routes/users.tsx
new file mode 100644
index 0000000000..64ca3ce156
--- /dev/null
+++ b/examples/react/start-otel/src/routes/users.tsx
@@ -0,0 +1,49 @@
+import { Link, Outlet, createFileRoute } from '@tanstack/react-router'
+import type { User } from '../utils/users'
+
+export const Route = createFileRoute('/users')({
+  loader: async () => {
+    const res = await fetch('/api/users')
+
+    if (!res.ok) {
+      throw new Error('Unexpected status code')
+    }
+
+    const data = await res.json()
+
+    return data as Array<User>
+  },
+  component: UsersComponent,
+})
+
+function UsersComponent() {
+  const users = Route.useLoaderData()
+
+  return (
+    <div className="p-2 flex gap-2">
+      <ul className="list-disc pl-4">
+        {[
+          ...users,
+          { id: 'i-do-not-exist', name: 'Non-existent User', email: '' },
+        ].map((user) => {
+          return (
+            <li key={user.id} className="whitespace-nowrap">
+              <Link
+                to="/users/$userId"
+                params={{
+                  userId: String(user.id),
+                }}
+                className="block py-1 text-blue-800 hover:text-blue-600"
+                activeProps={{ className: 'text-black font-bold' }}
+              >
+                <div>{user.name}</div>
+              </Link>
+            </li>
+          )
+        })}
+      </ul>
+      <hr />
+      <Outlet />
+    </div>
+  )
+}
diff --git a/examples/react/start-otel/src/server.ts b/examples/react/start-otel/src/server.ts
new file mode 100644
index 0000000000..2b19fb8b90
--- /dev/null
+++ b/examples/react/start-otel/src/server.ts
@@ -0,0 +1,21 @@
+import handler from '@tanstack/react-start/server-entry'
+import { tracer } from './utils/tracer'
+
+import './otel'
+
+export default {
+  async fetch(request: Request) {
+    return tracer.startActiveSpan(
+      `${request.method} ${new URL(request.url).pathname}`,
+      async (span) => {
+        span.setAttribute('http.method', request.method)
+        span.setAttribute('http.url', request.url)
+        span.setAttribute('http.route', new URL(request.url).pathname)
+        const response = await handler.fetch(request)
+        span.setAttribute('http.status_code', response.status)
+        span.end()
+        return response
+      },
+    )
+  },
+}
diff --git a/examples/react/start-otel/src/styles/app.css b/examples/react/start-otel/src/styles/app.css
new file mode 100644
index 0000000000..c53c870665
--- /dev/null
+++ b/examples/react/start-otel/src/styles/app.css
@@ -0,0 +1,22 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+  html {
+    color-scheme: light dark;
+  }
+
+  * {
+    @apply border-gray-200 dark:border-gray-800;
+  }
+
+  html,
+  body {
+    @apply text-gray-900 bg-gray-50 dark:bg-gray-950 dark:text-gray-200;
+  }
+
+  .using-mouse * {
+    outline: none !important;
+  }
+}
diff --git a/examples/react/start-otel/src/utils/loggingMiddleware.tsx b/examples/react/start-otel/src/utils/loggingMiddleware.tsx
new file mode 100644
index 0000000000..3ea9a06439
--- /dev/null
+++ b/examples/react/start-otel/src/utils/loggingMiddleware.tsx
@@ -0,0 +1,41 @@
+import { createMiddleware } from '@tanstack/react-start'
+
+const preLogMiddleware = createMiddleware({ type: 'function' })
+  .client(async (ctx) => {
+    const clientTime = new Date()
+
+    return ctx.next({
+      context: {
+        clientTime,
+      },
+      sendContext: {
+        clientTime,
+      },
+    })
+  })
+  .server(async (ctx) => {
+    const serverTime = new Date()
+
+    return ctx.next({
+      sendContext: {
+        serverTime,
+        durationToServer:
+          serverTime.getTime() - ctx.context.clientTime.getTime(),
+      },
+    })
+  })
+
+export const logMiddleware = createMiddleware({ type: 'function' })
+  .middleware([preLogMiddleware])
+  .client(async (ctx) => {
+    const res = await ctx.next()
+
+    const now = new Date()
+    console.log('Client Req/Res:', {
+      duration: now.getTime() - res.context.clientTime.getTime(),
+      durationToServer: res.context.durationToServer,
+      durationFromServer: now.getTime() - res.context.serverTime.getTime(),
+    })
+
+    return res
+  })
diff --git a/examples/react/start-otel/src/utils/posts.tsx b/examples/react/start-otel/src/utils/posts.tsx
new file mode 100644
index 0000000000..476f6fa924
--- /dev/null
+++ b/examples/react/start-otel/src/utils/posts.tsx
@@ -0,0 +1,53 @@
+import { notFound } from '@tanstack/react-router'
+import { createServerFn } from '@tanstack/react-start'
+import { SpanStatusCode } from '@opentelemetry/api'
+import { tracer } from './tracer'
+
+export type PostType = {
+  id: number
+  title: string
+  body: string
+}
+
+export const fetchPost = createServerFn({ method: 'POST' })
+  .inputValidator((d: string) => d)
+  .handler(async ({ data, context }) => {
+    console.log('Request context:', context)
+    console.info(`Fetching post with id ${data}...`)
+    const res = await fetch(
+      `https://jsonplaceholder.typicode.com/posts/${data}`,
+    )
+    if (!res.ok) {
+      if (res.status === 404) {
+        throw notFound()
+      }
+
+      throw new Error('Failed to fetch post')
+    }
+
+    const post = await res.json()
+
+    return post as PostType
+  })
+
+export const fetchPosts = createServerFn().handler(async () => {
+  return tracer.startActiveSpan('fetchPosts', async (span) => {
+    try {
+    console.info('Fetching posts...')
+    const res = await fetch('https://jsonplaceholder.typicode.com/posts')
+    if (!res.ok) {
+      throw new Error('Failed to fetch posts')
+    }
+
+    const posts = await res.json()
+
+    span.setStatus({ code: SpanStatusCode.OK })
+      return (posts as Array<PostType>).slice(0, 10)
+    } catch (error: any) {
+      span.recordException(error)
+      throw error
+    } finally {
+      span.end()
+    }
+  })
+})
diff --git a/examples/react/start-otel/src/utils/seo.ts b/examples/react/start-otel/src/utils/seo.ts
new file mode 100644
index 0000000000..d18ad84b74
--- /dev/null
+++ b/examples/react/start-otel/src/utils/seo.ts
@@ -0,0 +1,33 @@
+export const seo = ({
+  title,
+  description,
+  keywords,
+  image,
+}: {
+  title: string
+  description?: string
+  image?: string
+  keywords?: string
+}) => {
+  const tags = [
+    { title },
+    { name: 'description', content: description },
+    { name: 'keywords', content: keywords },
+    { name: 'twitter:title', content: title },
+    { name: 'twitter:description', content: description },
+    { name: 'twitter:creator', content: '@tannerlinsley' },
+    { name: 'twitter:site', content: '@tannerlinsley' },
+    { name: 'og:type', content: 'website' },
+    { name: 'og:title', content: title },
+    { name: 'og:description', content: description },
+    ...(image
+      ? [
+          { name: 'twitter:image', content: image },
+          { name: 'twitter:card', content: 'summary_large_image' },
+          { name: 'og:image', content: image },
+        ]
+      : []),
+  ]
+
+  return tags
+}
diff --git a/examples/react/start-otel/src/utils/tracer.ts b/examples/react/start-otel/src/utils/tracer.ts
new file mode 100644
index 0000000000..61461f9b07
--- /dev/null
+++ b/examples/react/start-otel/src/utils/tracer.ts
@@ -0,0 +1,3 @@
+import { trace } from '@opentelemetry/api'
+
+export const tracer = trace.getTracer('tanstack-start')
diff --git a/examples/react/start-otel/src/utils/users.tsx b/examples/react/start-otel/src/utils/users.tsx
new file mode 100644
index 0000000000..7ba645b383
--- /dev/null
+++ b/examples/react/start-otel/src/utils/users.tsx
@@ -0,0 +1,5 @@
+export type User = {
+  id: number
+  name: string
+  email: string
+}
diff --git a/examples/react/start-otel/tailwind.config.mjs b/examples/react/start-otel/tailwind.config.mjs
new file mode 100644
index 0000000000..e49f4eb776
--- /dev/null
+++ b/examples/react/start-otel/tailwind.config.mjs
@@ -0,0 +1,4 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+  content: ['./src/**/*.{js,jsx,ts,tsx}'],
+}
diff --git a/examples/react/start-otel/tsconfig.json b/examples/react/start-otel/tsconfig.json
new file mode 100644
index 0000000000..3a9fb7cd71
--- /dev/null
+++ b/examples/react/start-otel/tsconfig.json
@@ -0,0 +1,22 @@
+{
+  "include": ["**/*.ts", "**/*.tsx"],
+  "compilerOptions": {
+    "strict": true,
+    "esModuleInterop": true,
+    "jsx": "react-jsx",
+    "module": "ESNext",
+    "moduleResolution": "Bundler",
+    "lib": ["DOM", "DOM.Iterable", "ES2022"],
+    "isolatedModules": true,
+    "resolveJsonModule": true,
+    "skipLibCheck": true,
+    "target": "ES2022",
+    "allowJs": true,
+    "forceConsistentCasingInFileNames": true,
+    "baseUrl": ".",
+    "paths": {
+      "~/*": ["./src/*"]
+    },
+    "noEmit": true
+  }
+}
diff --git a/examples/react/start-otel/vite.config.ts b/examples/react/start-otel/vite.config.ts
new file mode 100644
index 0000000000..c7851284b6
--- /dev/null
+++ b/examples/react/start-otel/vite.config.ts
@@ -0,0 +1,19 @@
+import { tanstackStart } from '@tanstack/react-start/plugin/vite'
+import { defineConfig } from 'vite'
+import tsConfigPaths from 'vite-tsconfig-paths'
+import viteReact from '@vitejs/plugin-react'
+
+export default defineConfig({
+  server: {
+    port: 3000,
+  },
+  plugins: [
+    tsConfigPaths({
+      projects: ['./tsconfig.json'],
+    }),
+    tanstackStart({
+      srcDirectory: 'src',
+    }),
+    viteReact(),
+  ],
+})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e42bf3c4a1..0f99885e41 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -5353,7 +5353,7 @@ importers:
         version: 7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
       vitest:
         specifier: ^3.2.4
-        version: 3.2.4(@types/node@22.10.2)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.6.0)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.1)(msw@2.7.0(@types/node@22.10.2)(typescript@5.9.2))(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
+        version: 3.2.4(@types/node@22.10.2)(@vitest/browser@3.0.6(@types/node@22.10.2)(playwright@1.52.0)(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))(vitest@3.2.4))(@vitest/ui@3.0.6(vitest@3.2.4))(jiti@2.6.0)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.1)(msw@2.7.0(@types/node@22.10.2)(typescript@5.9.2))(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
       web-vitals:
         specifier: ^5.1.0
         version: 5.1.0
@@ -5715,6 +5715,73 @@ importers:
         specifier: ^5.1.4
         version: 5.1.4(typescript@5.8.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))
 
+  examples/react/start-otel:
+    dependencies:
+      '@opentelemetry/api':
+        specifier: ^1.9.0
+        version: 1.9.0
+      '@opentelemetry/exporter-trace-otlp-proto':
+        specifier: ^0.206.0
+        version: 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-node':
+        specifier: ^0.206.0
+        version: 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-trace-node':
+        specifier: ^2.1.0
+        version: 2.1.0(@opentelemetry/api@1.9.0)
+      '@tanstack/react-router':
+        specifier: workspace:*
+        version: link:../../../packages/react-router
+      '@tanstack/react-router-devtools':
+        specifier: workspace:^
+        version: link:../../../packages/react-router-devtools
+      '@tanstack/react-start':
+        specifier: workspace:*
+        version: link:../../../packages/react-start
+      react:
+        specifier: ^19.0.0
+        version: 19.0.0
+      react-dom:
+        specifier: ^19.0.0
+        version: 19.0.0(react@19.0.0)
+      tailwind-merge:
+        specifier: ^2.6.0
+        version: 2.6.0
+      zod:
+        specifier: ^3.24.2
+        version: 3.25.57
+    devDependencies:
+      '@types/node':
+        specifier: 22.10.2
+        version: 22.10.2
+      '@types/react':
+        specifier: ^19.0.8
+        version: 19.0.8
+      '@types/react-dom':
+        specifier: ^19.0.3
+        version: 19.0.3(@types/react@19.0.8)
+      '@vitejs/plugin-react':
+        specifier: ^4.6.0
+        version: 4.7.0(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))
+      autoprefixer:
+        specifier: ^10.4.20
+        version: 10.4.20(postcss@8.5.6)
+      postcss:
+        specifier: ^8.5.1
+        version: 8.5.6
+      tailwindcss:
+        specifier: ^3.4.17
+        version: 3.4.17
+      typescript:
+        specifier: ^5.7.2
+        version: 5.9.2
+      vite:
+        specifier: ^7.1.7
+        version: 7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
+      vite-tsconfig-paths:
+        specifier: ^5.1.4
+        version: 5.1.4(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))
+
   examples/react/start-streaming-data-from-server-functions:
     dependencies:
       '@tanstack/react-router':
@@ -9621,6 +9688,168 @@ packages:
   '@open-draft/until@2.1.0':
     resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
 
+  '@opentelemetry/api-logs@0.206.0':
+    resolution: {integrity: sha512-yIVDu9jX//nV5wSMLZLdHdb1SKHIMj9k+wQVFtln5Flcgdldz9BkHtavvExQiJqBZg2OpEEJEZmzQazYztdz2A==}
+    engines: {node: '>=8.0.0'}
+
+  '@opentelemetry/api@1.9.0':
+    resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
+    engines: {node: '>=8.0.0'}
+
+  '@opentelemetry/context-async-hooks@2.1.0':
+    resolution: {integrity: sha512-zOyetmZppnwTyPrt4S7jMfXiSX9yyfF0hxlA8B5oo2TtKl+/RGCy7fi4DrBfIf3lCPrkKsRBWZZD7RFojK7FDg==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.0.0 <1.10.0'
+
+  '@opentelemetry/core@2.1.0':
+    resolution: {integrity: sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.0.0 <1.10.0'
+
+  '@opentelemetry/exporter-logs-otlp-grpc@0.206.0':
+    resolution: {integrity: sha512-kJKxKBaGwqWop95d6tcluz260IWwIgOG0BH8oVm6429tg8LxY2PJb7Om8d5s+5vOFM8DkUYCnIpn9d/13/RcKQ==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/exporter-logs-otlp-http@0.206.0':
+    resolution: {integrity: sha512-VWcHEnS+1kN+sQTAdCgSn2anqHPxY1/e52fhpe2mcSnEaXI1srFf3RU5DAu7hzQO6T9DPQzOKG8kc76vCtyYDw==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/exporter-logs-otlp-proto@0.206.0':
+    resolution: {integrity: sha512-CsYNXJwkn1qCXJGE+/JvvYucAjL8rpaxa2hnl+tDP6M5E0O3UVa8zG4ZUEebjr5J5Nc32egvslEZx5rgNOp3lQ==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/exporter-metrics-otlp-grpc@0.206.0':
+    resolution: {integrity: sha512-/qGIwVa27BSGqzULB34O+UtEVl4isc+gEd2ydMfZVidWpdkJYbMeZZYBWi4z6giD0w0Dep5k/NIJ/lSEZoKEIg==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/exporter-metrics-otlp-http@0.206.0':
+    resolution: {integrity: sha512-u6ztHNbgNlFw3vCuOErGsiiEcDk9KB0pwd/Jv6aPnvV4oKJd/5K+lfiSjDpCFUh5UUFJdGmHtADxUgbRpYMPyA==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/exporter-metrics-otlp-proto@0.206.0':
+    resolution: {integrity: sha512-mLlmXmVOSwMw8Cm9RKz5ZuTUWW28lQWWIcy5cpEUhIrJ5cuSuTZ/PKIaa3+CHmcKkkF2pWFdBkzOIar9aApzoQ==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/exporter-prometheus@0.206.0':
+    resolution: {integrity: sha512-sCzW+vE2KhlDZhH73f7drr+d0kvlsqG02t9xGtG40c6t4hjgpa5qEwEZTzFo9s4djtUrmDBjwJ5S3NYuCERVKg==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/exporter-trace-otlp-grpc@0.206.0':
+    resolution: {integrity: sha512-/q8sU9wj20tT9m+529VXN9E9DzpvNui5Cict8onY/gRGeXqTav21xHkvmv0FSpetb/29WS89drVjfI8/Mf2iWQ==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/exporter-trace-otlp-http@0.206.0':
+    resolution: {integrity: sha512-xiEhJZxE9yDb13FVW4XaF7J56boLv1NALOGEVu3F8jMC24iZmX5TSVRJCNGLWyy1Xb3N27Yu31kdSsmEBCnxyw==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/exporter-trace-otlp-proto@0.206.0':
+    resolution: {integrity: sha512-A3lGp39qqZGt6PU/9X682/4KdkDMu+jO+slnNCdm8Zki3AKEFulY2yYtz4rL0rah/liN+ENRsFQWI/B3xJiZGw==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/exporter-zipkin@2.1.0':
+    resolution: {integrity: sha512-0mEI0VDZrrX9t5RE1FhAyGz+jAGt96HSuXu73leswtY3L5YZD11gtcpARY2KAx/s6Z2+rj5Mhj566JsI2C7mfA==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.0.0
+
+  '@opentelemetry/instrumentation@0.206.0':
+    resolution: {integrity: sha512-anPU9GAn3vSH/0JFQZ4e626xRw8p8R21kxM7xammFk9BRhfDw1IpgqvFMllbb+1MSHHEX9EiUqYHJyWo/B6KGA==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/otlp-exporter-base@0.206.0':
+    resolution: {integrity: sha512-Rv54oSNKMHYS5hv+H5EGksfBUtvPQWFTK+Dk6MjJun9tOijCsFJrhRFvAqg5d67TWSMn+ZQYRKIeXh5oLVrpAQ==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/otlp-grpc-exporter-base@0.206.0':
+    resolution: {integrity: sha512-IA8EDbrB8OKtidMqErBY8sUc9mh03LOXuNPwp4/rdPrxSt45g1gBuZMovRXdEWfRyKKbF2E7MdipT2m11bs6SQ==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/otlp-transformer@0.206.0':
+    resolution: {integrity: sha512-Li2Cik1WnmNbU2mmTnw7DxvRiXhMcnAuTfAclP8y/zy7h5+GrLDpTZ+Z0XUs+Q3MLkb/h3ry4uFrC/z+2a6X7g==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': ^1.3.0
+
+  '@opentelemetry/propagator-b3@2.1.0':
+    resolution: {integrity: sha512-yOdHmFseIChYanddMMz0mJIFQHyjwbNhoxc65fEAA8yanxcBPwoFDoh1+WBUWAO/Z0NRgk+k87d+aFIzAZhcBw==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.0.0 <1.10.0'
+
+  '@opentelemetry/propagator-jaeger@2.1.0':
+    resolution: {integrity: sha512-QYo7vLyMjrBCUTpwQBF/e+rvP7oGskrSELGxhSvLj5gpM0az9oJnu/0O4l2Nm7LEhAff80ntRYKkAcSwVgvSVQ==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.0.0 <1.10.0'
+
+  '@opentelemetry/resources@2.1.0':
+    resolution: {integrity: sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.3.0 <1.10.0'
+
+  '@opentelemetry/sdk-logs@0.206.0':
+    resolution: {integrity: sha512-SQ2yTmqe4Mw9RI3a/glVkfjWPsXh6LySvnljXubiZq4zu+UP8NMJt2j82ZsYb+KpD7Eu+/41/7qlJnjdeVjz7Q==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.4.0 <1.10.0'
+
+  '@opentelemetry/sdk-metrics@2.1.0':
+    resolution: {integrity: sha512-J9QX459mzqHLL9Y6FZ4wQPRZG4TOpMCyPOh6mkr/humxE1W2S3Bvf4i75yiMW9uyed2Kf5rxmLhTm/UK8vNkAw==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.9.0 <1.10.0'
+
+  '@opentelemetry/sdk-node@0.206.0':
+    resolution: {integrity: sha512-t/2xYG1+pXK2M4jra48Gw6BS0E/hz4zYwuqC8G8JCTx9UQpCiFlaA3Yxbns79R1h6NbQz7NAe2kJO3/Jf9BoIA==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.3.0 <1.10.0'
+
+  '@opentelemetry/sdk-trace-base@2.1.0':
+    resolution: {integrity: sha512-uTX9FBlVQm4S2gVQO1sb5qyBLq/FPjbp+tmGoxu4tIgtYGmBYB44+KX/725RFDe30yBSaA9Ml9fqphe1hbUyLQ==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.3.0 <1.10.0'
+
+  '@opentelemetry/sdk-trace-node@2.1.0':
+    resolution: {integrity: sha512-SvVlBFc/jI96u/mmlKm86n9BbTCbQ35nsPoOohqJX6DXH92K0kTe73zGY5r8xoI1QkjR9PizszVJLzMC966y9Q==}
+    engines: {node: ^18.19.0 || >=20.6.0}
+    peerDependencies:
+      '@opentelemetry/api': '>=1.0.0 <1.10.0'
+
+  '@opentelemetry/semantic-conventions@1.37.0':
+    resolution: {integrity: sha512-JD6DerIKdJGmRp4jQyX5FlrQjA4tjOw1cvfsPAZXfOOEErMUHjPcPSICS+6WnM0nB0efSFARh0KAZss+bvExOA==}
+    engines: {node: '>=14'}
+
   '@parcel/watcher-android-arm64@2.5.1':
     resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
     engines: {node: '>= 10.0.0'}
@@ -13957,6 +14186,9 @@ packages:
     resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
     engines: {node: '>=6'}
 
+  import-in-the-middle@1.15.0:
+    resolution: {integrity: sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==}
+
   import-lazy@4.0.0:
     resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==}
     engines: {node: '>=8'}
@@ -14189,10 +14421,6 @@ packages:
     resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
     hasBin: true
 
-  jiti@2.4.2:
-    resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
-    hasBin: true
-
   jiti@2.6.0:
     resolution: {integrity: sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==}
     hasBin: true
@@ -14768,6 +14996,9 @@ packages:
   mlly@1.8.0:
     resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
 
+  module-details-from-path@1.0.4:
+    resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==}
+
   motion-dom@11.18.1:
     resolution: {integrity: sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==}
 
@@ -15530,6 +15761,10 @@ packages:
     resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
     engines: {node: '>=0.10.0'}
 
+  require-in-the-middle@8.0.1:
+    resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==}
+    engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'}
+
   requires-port@1.0.0:
     resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
 
@@ -17165,14 +17400,14 @@ snapshots:
 
   '@babel/helper-member-expression-to-functions@7.27.1':
     dependencies:
-      '@babel/traverse': 7.27.7
-      '@babel/types': 7.27.7
+      '@babel/traverse': 7.28.4
+      '@babel/types': 7.28.4
     transitivePeerDependencies:
       - supports-color
 
   '@babel/helper-module-imports@7.18.6':
     dependencies:
-      '@babel/types': 7.27.7
+      '@babel/types': 7.28.4
 
   '@babel/helper-module-imports@7.27.1':
     dependencies:
@@ -17210,7 +17445,7 @@ snapshots:
 
   '@babel/helper-optimise-call-expression@7.27.1':
     dependencies:
-      '@babel/types': 7.27.7
+      '@babel/types': 7.28.4
 
   '@babel/helper-plugin-utils@7.27.1': {}
 
@@ -17219,7 +17454,7 @@ snapshots:
       '@babel/core': 7.27.4
       '@babel/helper-member-expression-to-functions': 7.27.1
       '@babel/helper-optimise-call-expression': 7.27.1
-      '@babel/traverse': 7.27.7
+      '@babel/traverse': 7.28.4
     transitivePeerDependencies:
       - supports-color
 
@@ -18675,8 +18910,8 @@ snapshots:
 
   '@jridgewell/remapping@2.3.5':
     dependencies:
-      '@jridgewell/gen-mapping': 0.3.8
-      '@jridgewell/trace-mapping': 0.3.25
+      '@jridgewell/gen-mapping': 0.3.13
+      '@jridgewell/trace-mapping': 0.3.31
 
   '@jridgewell/resolve-uri@3.1.2': {}
 
@@ -18684,8 +18919,8 @@ snapshots:
 
   '@jridgewell/source-map@0.3.6':
     dependencies:
-      '@jridgewell/gen-mapping': 0.3.8
-      '@jridgewell/trace-mapping': 0.3.25
+      '@jridgewell/gen-mapping': 0.3.13
+      '@jridgewell/trace-mapping': 0.3.31
 
   '@jridgewell/sourcemap-codec@1.5.0': {}
 
@@ -19011,6 +19246,233 @@ snapshots:
 
   '@open-draft/until@2.1.0': {}
 
+  '@opentelemetry/api-logs@0.206.0':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+
+  '@opentelemetry/api@1.9.0': {}
+
+  '@opentelemetry/context-async-hooks@2.1.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+
+  '@opentelemetry/core@2.1.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/semantic-conventions': 1.37.0
+
+  '@opentelemetry/exporter-logs-otlp-grpc@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@grpc/grpc-js': 1.9.15
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-exporter-base': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-grpc-exporter-base': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-transformer': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-logs': 0.206.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/exporter-logs-otlp-http@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/api-logs': 0.206.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-exporter-base': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-transformer': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-logs': 0.206.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/exporter-logs-otlp-proto@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/api-logs': 0.206.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-exporter-base': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-transformer': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-logs': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-trace-base': 2.1.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/exporter-metrics-otlp-grpc@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@grpc/grpc-js': 1.9.15
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/exporter-metrics-otlp-http': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-exporter-base': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-grpc-exporter-base': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-transformer': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-metrics': 2.1.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/exporter-metrics-otlp-http@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-exporter-base': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-transformer': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-metrics': 2.1.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/exporter-metrics-otlp-proto@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/exporter-metrics-otlp-http': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-exporter-base': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-transformer': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-metrics': 2.1.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/exporter-prometheus@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-metrics': 2.1.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/exporter-trace-otlp-grpc@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@grpc/grpc-js': 1.9.15
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-exporter-base': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-grpc-exporter-base': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-transformer': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-trace-base': 2.1.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/exporter-trace-otlp-http@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-exporter-base': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-transformer': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-trace-base': 2.1.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/exporter-trace-otlp-proto@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-exporter-base': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-transformer': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-trace-base': 2.1.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/exporter-zipkin@2.1.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-trace-base': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/semantic-conventions': 1.37.0
+
+  '@opentelemetry/instrumentation@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/api-logs': 0.206.0
+      import-in-the-middle: 1.15.0
+      require-in-the-middle: 8.0.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/otlp-exporter-base@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-transformer': 0.206.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/otlp-grpc-exporter-base@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@grpc/grpc-js': 1.9.15
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-exporter-base': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/otlp-transformer': 0.206.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/otlp-transformer@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/api-logs': 0.206.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-logs': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-metrics': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-trace-base': 2.1.0(@opentelemetry/api@1.9.0)
+      protobufjs: 7.4.0
+
+  '@opentelemetry/propagator-b3@2.1.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/propagator-jaeger@2.1.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/resources@2.1.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/semantic-conventions': 1.37.0
+
+  '@opentelemetry/sdk-logs@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/api-logs': 0.206.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/sdk-metrics@2.1.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/sdk-node@0.206.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/api-logs': 0.206.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/exporter-logs-otlp-grpc': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/exporter-logs-otlp-http': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/exporter-logs-otlp-proto': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/exporter-metrics-otlp-grpc': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/exporter-metrics-otlp-http': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/exporter-metrics-otlp-proto': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/exporter-prometheus': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/exporter-trace-otlp-grpc': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/exporter-trace-otlp-http': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/exporter-trace-otlp-proto': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/exporter-zipkin': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/instrumentation': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/propagator-b3': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/propagator-jaeger': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-logs': 0.206.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-metrics': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-trace-base': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-trace-node': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/semantic-conventions': 1.37.0
+    transitivePeerDependencies:
+      - supports-color
+
+  '@opentelemetry/sdk-trace-base@2.1.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/semantic-conventions': 1.37.0
+
+  '@opentelemetry/sdk-trace-node@2.1.0(@opentelemetry/api@1.9.0)':
+    dependencies:
+      '@opentelemetry/api': 1.9.0
+      '@opentelemetry/context-async-hooks': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0)
+      '@opentelemetry/sdk-trace-base': 2.1.0(@opentelemetry/api@1.9.0)
+
+  '@opentelemetry/semantic-conventions@1.37.0': {}
+
   '@parcel/watcher-android-arm64@2.5.1':
     optional: true
 
@@ -20568,7 +21030,7 @@ snapshots:
     dependencies:
       '@ampproject/remapping': 2.3.0
       enhanced-resolve: 5.18.1
-      jiti: 2.4.2
+      jiti: 2.6.0
       lightningcss: 1.29.2
       magic-string: 0.30.17
       source-map-js: 1.2.1
@@ -21767,6 +22229,10 @@ snapshots:
     dependencies:
       acorn: 8.14.1
 
+  acorn-import-attributes@1.9.5(acorn@8.15.0):
+    dependencies:
+      acorn: 8.15.0
+
   acorn-jsx@5.3.2(acorn@8.14.1):
     dependencies:
       acorn: 8.14.1
@@ -21984,7 +22450,7 @@ snapshots:
       '@babel/core': 7.27.4
       '@babel/helper-module-imports': 7.18.6
       '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.4)
-      '@babel/types': 7.27.7
+      '@babel/types': 7.28.4
       html-entities: 2.3.3
       parse5: 7.3.0
       validate-html-nesting: 1.2.2
@@ -21994,7 +22460,7 @@ snapshots:
       '@babel/core': 7.27.7
       '@babel/helper-module-imports': 7.18.6
       '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.7)
-      '@babel/types': 7.27.7
+      '@babel/types': 7.28.4
       html-entities: 2.3.3
       parse5: 7.3.0
       validate-html-nesting: 1.2.2
@@ -22004,7 +22470,7 @@ snapshots:
       '@babel/core': 7.28.4
       '@babel/helper-module-imports': 7.18.6
       '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4)
-      '@babel/types': 7.27.7
+      '@babel/types': 7.28.4
       html-entities: 2.3.3
       parse5: 7.3.0
       validate-html-nesting: 1.2.2
@@ -23866,6 +24332,13 @@ snapshots:
       parent-module: 1.0.1
       resolve-from: 4.0.0
 
+  import-in-the-middle@1.15.0:
+    dependencies:
+      acorn: 8.15.0
+      acorn-import-attributes: 1.9.5(acorn@8.15.0)
+      cjs-module-lexer: 1.4.3
+      module-details-from-path: 1.0.4
+
   import-lazy@4.0.0: {}
 
   import-local@3.2.0:
@@ -24058,8 +24531,6 @@ snapshots:
 
   jiti@1.21.7: {}
 
-  jiti@2.4.2: {}
-
   jiti@2.6.0: {}
 
   jju@1.4.0: {}
@@ -24602,6 +25073,8 @@ snapshots:
       pkg-types: 1.3.1
       ufo: 1.6.1
 
+  module-details-from-path@1.0.4: {}
+
   motion-dom@11.18.1:
     dependencies:
       motion-utils: 11.18.1
@@ -25181,7 +25654,7 @@ snapshots:
   postcss-load-config@4.0.2(postcss@8.5.6):
     dependencies:
       lilconfig: 3.1.3
-      yaml: 2.7.0
+      yaml: 2.8.1
     optionalDependencies:
       postcss: 8.5.6
 
@@ -25543,6 +26016,13 @@ snapshots:
 
   require-from-string@2.0.2: {}
 
+  require-in-the-middle@8.0.1:
+    dependencies:
+      debug: 4.4.3
+      module-details-from-path: 1.0.4
+    transitivePeerDependencies:
+      - supports-color
+
   requires-port@1.0.0: {}
 
   resolve-cwd@3.0.0:
@@ -26044,7 +26524,7 @@ snapshots:
 
   sucrase@3.35.0:
     dependencies:
-      '@jridgewell/gen-mapping': 0.3.8
+      '@jridgewell/gen-mapping': 0.3.13
       commander: 4.1.1
       glob: 10.4.5
       lines-and-columns: 1.2.4
@@ -26351,7 +26831,7 @@ snapshots:
   typedoc-plugin-frontmatter@1.3.0(typedoc-plugin-markdown@4.9.0(typedoc@0.28.14(typescript@5.9.2))):
     dependencies:
       typedoc-plugin-markdown: 4.9.0(typedoc@0.28.14(typescript@5.9.2))
-      yaml: 2.7.0
+      yaml: 2.8.1
 
   typedoc-plugin-markdown@4.9.0(typedoc@0.28.14(typescript@5.9.2)):
     dependencies:
@@ -26700,7 +27180,7 @@ snapshots:
 
   vite-tsconfig-paths@5.1.4(typescript@5.8.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)):
     dependencies:
-      debug: 4.4.0
+      debug: 4.4.3
       globrex: 0.1.2
       tsconfck: 3.1.4(typescript@5.8.2)
     optionalDependencies:
@@ -26711,7 +27191,7 @@ snapshots:
 
   vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)):
     dependencies:
-      debug: 4.4.0
+      debug: 4.4.3
       globrex: 0.1.2
       tsconfck: 3.1.4(typescript@5.8.3)
     optionalDependencies:
@@ -26722,7 +27202,7 @@ snapshots:
 
   vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)):
     dependencies:
-      debug: 4.4.0
+      debug: 4.4.3
       globrex: 0.1.2
       tsconfck: 3.1.4(typescript@5.9.2)
     optionalDependencies:
@@ -26752,7 +27232,7 @@ snapshots:
     optionalDependencies:
       vite: 7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1)
 
-  vitest@3.2.4(@types/node@22.10.2)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.6.0)(jsdom@25.0.1)(lightningcss@1.30.1)(msw@2.7.0(@types/node@22.10.2)(typescript@5.9.2))(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1):
+  vitest@3.2.4(@types/node@22.10.2)(@vitest/browser@3.0.6(@types/node@22.10.2)(playwright@1.52.0)(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))(vitest@3.2.4))(@vitest/ui@3.0.6(vitest@3.2.4))(jiti@2.6.0)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.1)(msw@2.7.0(@types/node@22.10.2)(typescript@5.9.2))(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1):
     dependencies:
       '@types/chai': 5.2.2
       '@vitest/expect': 3.2.4
@@ -26781,7 +27261,7 @@ snapshots:
       '@types/node': 22.10.2
       '@vitest/browser': 3.0.6(@types/node@22.10.2)(playwright@1.52.0)(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))(vitest@3.2.4)
       '@vitest/ui': 3.0.6(vitest@3.2.4)
-      jsdom: 25.0.1
+      jsdom: 27.0.0(postcss@8.5.6)
     transitivePeerDependencies:
       - jiti
       - less
@@ -26796,7 +27276,7 @@ snapshots:
       - tsx
       - yaml
 
-  vitest@3.2.4(@types/node@22.10.2)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.6.0)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.1)(msw@2.7.0(@types/node@22.10.2)(typescript@5.9.2))(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1):
+  vitest@3.2.4(@types/node@22.10.2)(@vitest/browser@3.0.6)(@vitest/ui@3.0.6)(jiti@2.6.0)(jsdom@25.0.1)(lightningcss@1.30.1)(msw@2.7.0(@types/node@22.10.2)(typescript@5.9.2))(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1):
     dependencies:
       '@types/chai': 5.2.2
       '@vitest/expect': 3.2.4
@@ -26825,7 +27305,7 @@ snapshots:
       '@types/node': 22.10.2
       '@vitest/browser': 3.0.6(@types/node@22.10.2)(playwright@1.52.0)(typescript@5.9.2)(vite@7.1.7(@types/node@22.10.2)(jiti@2.6.0)(lightningcss@1.30.1)(terser@5.37.0)(tsx@4.20.3)(yaml@2.8.1))(vitest@3.2.4)
       '@vitest/ui': 3.0.6(vitest@3.2.4)
-      jsdom: 27.0.0(postcss@8.5.6)
+      jsdom: 25.0.1
     transitivePeerDependencies:
       - jiti
       - less

From 4780458d6e54a3b7cdbef09d32dd307a3b858211 Mon Sep 17 00:00:00 2001
From: Jamie Davenport <1329874+jamiedavenport@users.noreply.github.com>
Date: Mon, 20 Oct 2025 21:28:08 +0100
Subject: [PATCH 2/2] Improve the server entrypoint tracing

---
 examples/react/start-otel/src/server.ts | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/examples/react/start-otel/src/server.ts b/examples/react/start-otel/src/server.ts
index 2b19fb8b90..6bfb535887 100644
--- a/examples/react/start-otel/src/server.ts
+++ b/examples/react/start-otel/src/server.ts
@@ -8,13 +8,19 @@ export default {
     return tracer.startActiveSpan(
       `${request.method} ${new URL(request.url).pathname}`,
       async (span) => {
-        span.setAttribute('http.method', request.method)
-        span.setAttribute('http.url', request.url)
-        span.setAttribute('http.route', new URL(request.url).pathname)
-        const response = await handler.fetch(request)
-        span.setAttribute('http.status_code', response.status)
-        span.end()
-        return response
+        try {
+          span.setAttribute('http.method', request.method)
+          span.setAttribute('http.url', request.url)
+          span.setAttribute('http.route', new URL(request.url).pathname)
+          const response = await handler.fetch(request)
+          span.setAttribute('http.status_code', response.status)
+          return response
+        } catch (error: any) {
+          span.recordException(error)
+          throw error
+        } finally {
+          span.end()
+        }
       },
     )
   },
