| 201 | + | ## Routes tab |
| 202 | + | </Link> |
| 203 | + | |
| 204 | + | The Routes tab shows the full route tree produced by the file-system router. Every page, layout, middleware, API route, error boundary, loading state, fallback, template, and named outlet is listed. |
| 205 | + | |
| 206 | + | {/* Screenshot: the Routes tab with a filter input, type filter buttons (active, all, page, layout, middleware, api, etc.) with count badges, a "12 of 28 routes" counter, and a table with Route, Type, file-type icon, and Source columns. Some rows have a green left border indicating they match the current path. */} |
| 207 | + | <ThemedImage light="/devtools-routes-light.webp" dark="/devtools-routes-dark.webp" alt="Routes tab" /> |
| 208 | + | |
| 209 | + | <Link name="filtering-routes"> |
| 210 | + | ### Filtering routes |
| 211 | + | </Link> |
| 212 | + | |
| 213 | + | | Control | How to use it | |
| 214 | + | |---------|---------------| |
| 215 | + | | Text filter | Type a path fragment, filename, outlet name, or HTTP method to narrow the list | |
| 216 | + | | Type buttons | Click a type (page, layout, middleware, api, error, loading, fallback, template, outlet) to show only that type. The count badge on each button tells you how many routes of that type exist | |
| 217 | + | | Active toggle | Click "active" to hide everything that does not match the current server pathname. This is useful to see exactly which layouts, middlewares, and pages are involved in rendering the current URL | |
| 218 | + | |
| 219 | + | <Link name="understanding-active-routes"> |
| 220 | + | ### Understanding active routes |
| 221 | + | </Link> |
| 222 | + | |
| 223 | + | Routes matching the current server pathname are highlighted with a green left border. The matching accounts for dynamic segments (`[param]`), optional parameters (`[[optional]]`), and catch-all patterns (`[...slug]`). Layouts, middlewares, and templates match as prefixes (they are active for all child paths), while pages must match exactly. |
| 224 | + | |
| 225 | + | > **Note:** the pathname used for matching is the **server pathname** (after any rewrites), not the client-visible URL. |
| 226 | + | |
| 227 | + | <Link name="opening-source-files"> |
| 228 | + | ### Opening source files |
| 229 | + | </Link> |
| 230 | + | |
| 231 | + | Each route row shows a file-type icon (React/JSX, TypeScript, MDX, etc.) and the relative source path. Click the source path to open the file in VS Code. |
| 232 | + | |
| 233 | + | <Link name="component-routes"> |
| 234 | + | ### Component routes |
| 235 | + | </Link> |
| 236 | + | |
| 237 | + | Below the file-router tree, a **Component Routes** section appears if your app registers routes via `<Route>` components in code. Each entry shows the route pattern, type (server, client, or fallback), and flags like `remote`, `exact`, or `loading`. Active component routes display the matched path parameters inline. |
| 238 | + | |
| 239 | + | <Link name="outlets-tab"> |
| 240 | + | ## Outlets tab |
| 241 | + | </Link> |
| 242 | + | |
| 243 | + | The Outlets tab lists every named outlet currently rendered on the page. Outlets are the named slots (`@sidebar`, `@content`, etc.) that layouts receive as props, plus `PAGE_ROOT` for the root rendering slot. |
| 244 | + | |
| 245 | + | {/* Screenshot: the Outlets tab showing "Host URL: http://localhost:3000/products" at the top and a grid of outlet cards. One card shows "@sidebar" with a "router" badge and eye/refresh icons. Another shows "PAGE_ROOT" with a "static" badge. A colored dashed overlay is visible on the page behind the panel, highlighting the "@sidebar" region with a label. */} |
| 246 | + | <ThemedImage light="/devtools-outlets-light.webp" dark="/devtools-outlets-dark.webp" alt="Outlets tab" /> |
| 247 | + | |
| 248 | + | <Link name="what-each-outlet-card-shows"> |
| 249 | + | ### What each outlet card shows |
| 250 | + | </Link> |
| 251 | + | |
| 252 | + | | Field | Meaning | |
| 253 | + | |-------|---------| |
| 254 | + | | Name | The outlet identifier | |
| 255 | + | | URL | The URL the outlet content was loaded from (if applicable) | |
| 256 | + | | Badge | How the outlet is managed: `router` (file-router), `remote` (fetched from another server), `live` (streaming), `defer` (lazily loaded), or `static` | |
| 257 | + | |
| 258 | + | <Link name="highlighting-outlets-on-the-page"> |
| 259 | + | ### Highlighting outlets on the page |
| 260 | + | </Link> |
| 261 | + | |
| 262 | + | Hover over any outlet card. A colored dashed rectangle appears around that outlet's rendered area on the page, with a label showing the outlet name. Each outlet gets a distinct color so you can visually map the cards to sections of the page. |
| 263 | + | |
| 264 | + | The highlight overlay handles edge cases: hidden marker elements, outlets that render as multiple sibling elements (the overlay covers the union bounding rect), and full-screen backdrop elements (which are filtered out so the actual content is highlighted). |
| 265 | + | |
| 266 | + | <Link name="scrolling-and-refreshing"> |
| 267 | + | ### Scrolling and refreshing |
| 268 | + | </Link> |
| 269 | + | |
| 270 | + | | Action | What it does | |
| 271 | + | |--------|-------------| |
| 272 | + | | <EyeIcon /> | Scrolls the page to the outlet's position | |
| 273 | + | | <RefreshIcon /> | Re-renders that single outlet without a full page reload — useful when you want to test server-side changes for one section of the page without navigating away | |
| 274 | + | |
| 275 | + | <Link name="remotes-tab"> |
| 276 | + | ## Remotes tab |
| 277 | + | </Link> |
| 278 | + | |
| 279 | + | If your app uses `<RemoteComponent>` to load RSC content from other react-server instances, the Remotes tab shows each one. |
| 280 | + | |
| 281 | + | {/* Screenshot: the Remotes tab showing two remote component cards. Each card has a URL like "http://localhost:3001/widget", an outlet name, and property badges (TTL, live). Action buttons for external link, eye, and arrow-right are visible. */} |
| 282 | + | <ThemedImage light="/devtools-remotes-light.webp" dark="/devtools-remotes-dark.webp" alt="Remotes tab" /> |
| 283 | + | |
| 284 | + | Each card shows: |
| 285 | + | |
| 286 | + | | Field | Meaning | |
| 287 | + | |-------|---------| |
| 288 | + | | Remote URL | The URL the component is fetched from. Click <ExternalLinkIcon /> to open it in a new browser tab | |
| 289 | + | | Outlet name | The outlet this remote component renders into | |
| 290 | + | | TTL badge | How long the response is cached | |
| 291 | + | | `isolate` badge | The component is rendered in a sandbox | |
| 292 | + | | `defer` badge | The component is loaded lazily | |
| 293 | + | | `live` badge | The component streams real-time updates | |
| 294 | + | |
| 295 | + | Hover to highlight the remote component on the page. Click <EyeIcon /> to scroll to it. Click <ArrowRightIcon /> to jump to its outlet in the Outlets tab. |
| 296 | + | |
| 297 | + | <Link name="live-tab"> |
| 298 | + | ## Live tab |
| 299 | + | </Link> |
| 300 | + | |
| 301 | + | The Live tab monitors every `"use live"` component — async generator functions on the server that yield successive renders to the client. |
| 302 | + | |
| 303 | + | {/* Screenshot: the Live tab showing two component cards. The first shows "StatusPanel" with a green "running" badge, a "streaming" cyan badge, "yields: 42", "last yield: 2s ago", "started: 5m ago". The second shows "PriceTracker" with a violet "waiting" badge. */} |
| 304 | + | <ThemedImage light="/devtools-live-light.webp" dark="/devtools-live-dark.webp" alt="Live tab" /> |
| 305 | + | |
| 306 | + | Each card shows the component's name, its current state, and runtime statistics: |
| 307 | + | |
| 308 | + | | State | Meaning | |
| 309 | + | |-------|---------| |
| 310 | + | | `starting` | The generator is being initialized | |
| 311 | + | | `waiting` | Waiting before the next yield | |
| 312 | + | | `running` / `connected` | Actively streaming to the client | |
| 313 | + | | `finished` | The generator returned normally | |
| 314 | + | | `aborted` | The client disconnected | |
| 315 | + | | `error` | The generator threw an exception (the error message is shown inline) | |
| 316 | + | |
| 317 | + | A `streaming` badge appears while data is being sent. The card also shows how many times the generator has yielded, when the last yield happened, and when the component started. If the component is loaded from a remote server, a `remote` badge appears. |
| 318 | + | |
| 319 | + | <Link name="workers-tab"> |
| 320 | + | ## Workers tab |
| 321 | + | </Link> |
| 322 | + | |
| 323 | + | The Workers tab tracks `"use worker"` threads — both server-side Worker Threads (Node.js) and client-side Web Workers. |
| 324 | + | |
| 325 | + | {/* Screenshot: the Workers tab with a toolbar showing "3 workers · 2 server · 1 client" and All/server/client filter buttons. Below, worker entries show type tags (server/client), state tags (Ready/Spawning), module paths, call counts, error counts, last function name, spawn time, and last call time. */} |
| 326 | + | <ThemedImage light="/devtools-workers-light.webp" dark="/devtools-workers-dark.webp" alt="Workers tab" /> |
| 327 | + | |
| 328 | + | The toolbar summarizes how many workers exist, broken down by type. Use the filter buttons to show only server or only client workers. |
| 329 | + | |
| 330 | + | Each worker entry shows: |
| 331 | + | |
| 332 | + | | Field | Meaning | |
| 333 | + | |-------|---------| |
| 334 | + | | Type | `server` or `client` | |
| 335 | + | | State | `Spawning` (thread starting), `Ready` (idle), `Error` (last call failed), or `Restarting` | |
| 336 | + | | Module path | The file that defines the worker, shortened to the last few path segments | |
| 337 | + | | Call count | Total invocations and how many are currently in flight | |
| 338 | + | | Error / restart counts | Helps spot unstable workers | |
| 339 | + | | Last function | The name of the most recently called export | |
| 340 | + | | Timing | When the worker was spawned and when it was last invoked | |
| 341 | + | |
| 342 | + | <Link name="logs-tab"> |
| 343 | + | ## Logs tab |
| 344 | + | </Link> |
| 345 | + | |
| 346 | + | The Logs tab streams all server terminal output (`stdout` and `stderr`) into the browser so you don't need to switch back to the terminal. |
| 347 | + | |
| 348 | + | {/* Screenshot: the Logs tab with a toolbar showing "All (156)" / "stdout (140)" / "stderr (16)" filter buttons, a search input, and a "Clear" button. The log list shows timestamped entries with colorful ANSI-rendered text (green "[vite]" prefix, yellow warnings). A few stderr entries are tagged in red. */} |
| 349 | + | <ThemedImage light="/devtools-logs-light.webp" dark="/devtools-logs-dark.webp" alt="Logs tab" /> |
| 350 | + | |
| 351 | + | <Link name="filtering-logs"> |
| 352 | + | ### Filtering logs |
| 353 | + | </Link> |
| 354 | + | |
| 355 | + | | Control | How to use it | |
| 356 | + | |---------|---------------| |
| 357 | + | | Stream buttons | Click `stdout` or `stderr` to show only that stream. The count on each button tells you how many entries of that type exist | |
| 358 | + | | Search field | Type any text to filter log entries. The search matches against the plain text content with ANSI codes stripped | |
| 359 | + | |
| 360 | + | <Link name="reading-ansi-output"> |
| 361 | + | ### Reading ANSI output |
| 362 | + | </Link> |
| 363 | + | |
| 364 | + | Server logs often contain ANSI escape codes for colors and text styling. The Logs tab renders these faithfully — 4-bit, 8-bit, and 24-bit (true-color) sequences are all supported, including bold, italic, underline, and dim. What you see in the panel matches what you'd see in a terminal. |
| 365 | + | |
| 366 | + | <Link name="auto-scroll-behavior"> |
| 367 | + | ### Auto-scroll behavior |
| 368 | + | </Link> |
| 369 | + | |
| 370 | + | By default the log view stays pinned to the bottom so new entries scroll into view as they arrive. Scroll up to pause auto-scrolling. A **Scroll to bottom** button appears at the bottom of the panel — click it to resume. |
| 371 | + | |
| 372 | + | Click **Clear** in the toolbar to empty the log buffer. |
| 373 | + | |
| 374 | + | <Link name="element-highlighting"> |
| 375 | + | ## Element highlighting |
| 376 | + | </Link> |
| 377 | + | |
| 378 | + | Several tabs let you hover over an item to highlight the corresponding element on the page: |
| 379 | + | |
| 380 | + | - In the **Payload** tab, hovering a client reference highlights the DOM element rendered by that client component (green overlay). |
| 381 | + | - In the **Outlets** tab, hovering an outlet card highlights its rendered region (each outlet gets a unique color). |
| 382 | + | - In the **Remotes** tab, hovering a remote card highlights its rendered region the same way. |
| 383 | + | |
| 384 | + | The overlay is a colored dashed rectangle with a label badge showing the name. It repositions in real time as you scroll or resize the page. |
| 385 | + | |
| 386 | + | {/* Screenshot: a page with the Outlets tab open. One outlet card is being hovered, and on the page a colored dashed rectangle with rounded corners outlines the outlet's rendered area, with a label badge reading "@sidebar" above it. */} |
| 387 | + | <ThemedImage light="/devtools-highlighting-light.webp" dark="/devtools-highlighting-dark.webp" alt="Element highlighting" /> |
| 388 | + | |
| 389 | + | <Link name="how-devtools-works"> |
| 390 | + | ## How DevTools works |
| 391 | + | </Link> |
| 392 | + | |
| 393 | + | The panel UI runs inside an iframe served from `/__react_server_devtools__/*`. This keeps the DevTools React tree separate from your app — it won't interfere with your component state or styling. |
| 394 | + | |
| 395 | + | Three communication channels connect the parts: |
| 396 | + | |
| 397 | + | - **Host page → Iframe** (`postMessage`): RSC payloads (captured by intercepting `fetch`), outlet registrations, component routes, page-level size stats, navigation events, and theme changes. |
| 398 | + | - **Server → Iframe** (Socket.IO, `/__devtools__` namespace): live component state, server-side cache events, worker status, server logs, and the file-router manifest. The connection is established automatically when the panel opens. |
| 399 | + | - **Iframe → Server** (Socket.IO): cache invalidation requests and outlet refresh commands travel back over the same socket. |