Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
137 changes: 137 additions & 0 deletions src/content/reference/developer-tooling/react-performance-tracks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
title: React Performance tracks
Copy link

@rubennorte rubennorte Sep 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
title: React Performance tracks
title: React performance tracks

It feels weird to capitalize performance. I'd either capitalize everything or just React. There are other examples of this in the doc.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking is, Performance is capitalized here to align with "Performance panel" in the browser.

@rickhanlonii How do you feel about the naming?

version: experimental
---

<Experimental>

**This feature is experimental and is not available in a stable version of React yet.**

You can try it by upgrading React packages to the most recent experimental version:

- `react@experimental`
- `react-dom@experimental`
- `eslint-plugin-react-hooks@experimental`

Experimental versions of React may contain bugs. Don't use them in production.

</Experimental>

<Intro>

React Performance tracks are specialized custom entries that appear on the Performance panel's timeline.

</Intro>

These tracks are designed to provide developers with comprehensive insights into their React application's performance by visualizing React-specific events and metrics alongside other critical data sources such as network requests, JavaScript execution, and event loop activity, all synchronized on a unified timeline within the Performance panel for a complete understanding of application behavior.

<div style={{display: 'flex', justifyContent: 'center', marginBottom: '1rem'}}>
<img className="w-full light-image" src="/images/docs/performance-tracks/overview.png" alt="React Performance Tracks" />
<img className="w-full dark-image" src="/images/docs/performance-tracks/overview.dark.png" alt="React Performance Tracks" />
</div>

<InlineToc />

---

## Usage {/*usage*/}

React Performance tracks are only available in development and profiling builds of React:

- **Development**: enabled by default.
- **Profiling**: you can either wrap a subtree that you want to instrument with [`<Profiler>`](/reference/react/Profiler) component or have [React Developer Tools extension](/learn/react-developer-tools) enabled.

If enabled, tracks should appear automatically in the traces you record with the Performance panel of browsers that provide [extensibility APIs](https://developer.chrome.com/docs/devtools/performance/extension).

<Pitfall>

The profiling instrumentation that powers React Performance tracks adds some additional overhead, so it is disabled in production builds by default.

</Pitfall>

---

## Tracks {/*tracks*/}

### Scheduler {/*scheduler*/}

The Scheduler is an internal React concept used for managing tasks with different priorities. This track consists of 4 subtracks, each representing work of a specific priority:

- **Blocking** - The synchronous updates, which could've been initiated by user interactions.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

State updates from commits (layout effects, ref assignments, etc.) are also scheduled with a blocking priority. We should probably mention that too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "The synchronous updates" are referring to the application updates, not to the state updates.

I am not sure how to update it to clarify it more

- **Transition** - Non-blocking work that happens in the background, usually initiated via [`startTransition`](/reference/react/startTransition).
- **Suspense** - Work related to Suspense boundaries, such as displaying fallbacks or revealing content.
- **Idle** - The lowest priority work that is done when there are no other tasks with higher priority.

<div style={{display: 'flex', justifyContent: 'center', marginBottom: '1rem'}}>
<img className="w-full light-image" src="/images/docs/performance-tracks/scheduler.png" alt="Scheduler track" />
<img className="w-full dark-image" src="/images/docs/performance-tracks/scheduler.dark.png" alt="Scheduler track" />
</div>

#### Renders {/*renders*/}

Every render pass consists of multiple phases that you can see on a timeline:

- **Update** - this is what caused a new render pass.
- **Render** - React renders the updated subtree by calling render functions of components. You can see the rendered components subtree on [Components track](/reference/developer-tooling/react-performance-tracks#components), which follows the same color scheme.
- **Commit** - After rendering components, React will submit the changes to the DOM and run layout effects, like [`useLayoutEffect`](/reference/react/useLayoutEffect).
- **Remaining Effects** - React runs passive effects of a rendered subtree. This usually happens after the paint, and this is when React runs hooks like [`useEffect`](/reference/react/useEffect). One known exception is user interactions, like clicks, or other discrete events. In this scenario, this phase could run before the paint.

<div style={{display: 'flex', justifyContent: 'center', marginBottom: '1rem'}}>
<img className="w-full light-image" src="/images/docs/performance-tracks/scheduler-update.png" alt="Scheduler track: updates" />
<img className="w-full dark-image" src="/images/docs/performance-tracks/scheduler-update.dark.png" alt="Scheduler track: updates" />
</div>

[Learn more about renders and commits](/learn/render-and-commit).

#### Cascading updates {/*cascading-updates*/}

Cascading updates is one of the patterns for performance regressions. If an update was scheduled during a render pass, React could discard completed work and start a new pass.

In development builds, React can show you which Component scheduled a new update. This includes both general updates and cascading ones. You can see the enhanced stack trace by clicking on the "Cascading update" entry, which should also display the name of the method that scheduled an update.

<div style={{display: 'flex', justifyContent: 'center', marginBottom: '1rem'}}>
<img className="w-full light-image" src="/images/docs/performance-tracks/scheduler-cascading-update.png" alt="Scheduler track: cascading updates" />
<img className="w-full dark-image" src="/images/docs/performance-tracks/scheduler-cascading-update.dark.png" alt="Scheduler track: cascading updates" />
</div>

[Learn more about Effects](/learn/you-might-not-need-an-effect).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a concrete example we can link to instead? Maybe even with a backlink telling people to use the profiler to spot cascading updates?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a section that explains fully the cascading updates. Only a small paragraph on https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state, where it is briefly mentioned.

That's a great idea for a separate task, we could add a section to it that explains how cascading updates could be spotted with Performance tracks. Will follow up.


### Components {/*components*/}

The Components track visualizes the durations of React components. They are displayed as a flamegraph, where each entry represents the duration of the corresponding component render and all its descendant children components.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should mention that not all components rendered are shown here. Only the ones taking more than a specific amount of time.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, added a note:

<Note>

Unlike renders, not all effects are shown on the Components track by default.

To maintain performance and prevent UI clutter, React will only display those effects, which had a duration of 0.05ms or longer, or triggered an update.

</Note>

I am working on a feature that will record effects that triggered an update, independent of their duration

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding that note, are we showing all components rendered, but not all effects, or are we also not showing all the renders?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All renders are showed, independent from their corresponding duration.

Not all effects are showed. With facebook/react#34648, we won't show the ones that took 0.05ms or less and didn't trigger any blocking updates.


<div style={{display: 'flex', justifyContent: 'center', marginBottom: '1rem'}}>
<img className="w-full light-image" src="/images/docs/performance-tracks/components-render.png" alt="Components track: render durations" />
<img className="w-full dark-image" src="/images/docs/performance-tracks/components-render.dark.png" alt="Components track: render durations" />
</div>

Similar to render durations, effect durations are also represented as a flamegraph, but with a different color scheme that aligns with the corresponding phase on the Scheduler track.

<div style={{display: 'flex', justifyContent: 'center', marginBottom: '1rem'}}>
<img className="w-full light-image" src="/images/docs/performance-tracks/components-effects.png" alt="Components track: effects durations" />
<img className="w-full dark-image" src="/images/docs/performance-tracks/components-effects.dark.png" alt="Components track: effects durations" />
</div>

<Note>

Unlike renders, not all effects are shown on the Components track by default.

To maintain performance and prevent UI clutter, React will only display those effects, which had a duration of 0.05ms or longer, or triggered an update.

</Note>

Additional events may be displayed during the render and effects phases:

- <span style={{padding: '0.125rem 0.25rem', backgroundColor: '#facc15', color: '#1f1f1fff'}}>Mount</span> - A corresponding subtree of component renders or effects was mounted.
- <span style={{padding: '0.125rem 0.25rem', backgroundColor: '#facc15', color: '#1f1f1fff'}}>Unmount</span> - A corresponding subtree of component renders or effects was unmounted.
- <span style={{padding: '0.125rem 0.25rem', backgroundColor: '#facc15', color: '#1f1f1fff'}}>Reconnect</span> - Similar to Mount, but limited to cases when [`<Activity>`](/reference/react/Activity) is used.
- <span style={{padding: '0.125rem 0.25rem', backgroundColor: '#facc15', color: '#1f1f1fff'}}>Disconnect</span> - Similar to Unmount, but limited to cases when [`<Activity>`](/reference/react/Activity) is used.

#### Changed props {/*changed-props*/}

In development builds, when you click on a component render entry, you can inspect potential changes in props. You can use this information to identify unnecessary renders.

<div style={{display: 'flex', justifyContent: 'center', marginBottom: '1rem'}}>
<img className="w-full light-image" src="/images/docs/performance-tracks/changed-props.png" alt="Components track: changed props" />
<img className="w-full dark-image" src="/images/docs/performance-tracks/changed-props.dark.png" alt="Components track: changed props" />
</div>
12 changes: 10 additions & 2 deletions src/sidebarReference.json
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,14 @@
"title": "Compiling Libraries",
"path": "/reference/react-compiler/compiling-libraries"
},
{
"hasSectionHeader": true,
"sectionHeader": "Developer tooling"
},
{
"title": "React Performance tracks",
"path": "/reference/developer-tooling/react-performance-tracks"
},
{
"hasSectionHeader": true,
"sectionHeader": "eslint-plugin-react-hooks"
Expand Down Expand Up @@ -429,7 +437,7 @@
"path": "/reference/eslint-plugin-react-hooks/lints/incompatible-library",
"version": "rc"
},

{
"title": "preserve-manual-memoization",
"path": "/reference/eslint-plugin-react-hooks/lints/preserve-manual-memoization",
Expand All @@ -445,7 +453,7 @@
"path": "/reference/eslint-plugin-react-hooks/lints/refs",
"version": "rc"
},

{
"title": "set-state-in-effect",
"path": "/reference/eslint-plugin-react-hooks/lints/set-state-in-effect",
Expand Down