facebook/reactMITd083ec1Report / request removal

DevTools Profiler & Commit Data

React DevTools profiling has two halves: the backend renderer records commit metadata and tree mutations, while the frontend turns that information into commit trees and chart data. The result is a historical view of each root at a selected commit, rather than only the latest rendered tree.

This design exists because durations and change reasons describe a commit, while the flame graph and ranked charts also need the component hierarchy as it existed during that commit. The frontend therefore preserves an initial snapshot and replays operations in order.

Sources: packages/react-devtools-shared/src/backend/fiber/renderer.js:7240-7324, packages/react-devtools-shared/src/devtools/ProfilerStore.js:25-380, packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js:53-126

Core concepts

Commit profiling data

A commit record contains total duration, per-fiber actual and self durations, change descriptions, effect timings, priority, timestamp, and possible updaters.

Sources: packages/react-devtools-shared/src/backend/fiber/renderer.js:7262-7308

Operations

Operations are numeric tree mutations emitted for a commit; they include renderer and root identity, a string table, unmount batches, regular operations, and Suspense-related changes.

Sources: packages/react-devtools-shared/src/backend/fiber/renderer.js:1457-1474

Initial tree snapshot

The initial snapshot is the starting component tree captured when profiling begins; replaying each commit’s operations against it reconstructs later states.

Sources: packages/react-devtools-shared/src/devtools/ProfilerStore.js:25-380

ProfilerStore

ProfilerStore owns backend payloads, the completed frontend profiling model, initial snapshots, in-progress operations, and the queue used while retrieving profiling data.

Sources: packages/react-devtools-shared/src/devtools/ProfilerStore.js:25-380

ProfilingCache

ProfilingCache lazily computes and caches commit trees, fiber-to-commit lookups, flamegraph data, and ranked chart data.

Sources: packages/react-devtools-shared/src/devtools/ProfilingCache.js:28-99

CommitTree

A CommitTree is the frontend’s reconstructed tree for one root at one commit index. getCommitTree builds these trees sequentially and retains them by root.

Sources: packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js:53-126

What the backend records for a commit

The backend accumulates per-fiber durations in triples: fiber ID, actual duration, and self duration. getProfilingData converts those triples into fiberActualDurations and fiberSelfDurations, applying microsecond granularity formatting to both duration values.

The commit’s overall duration is derived from maxActualDuration; optional effectDuration and passiveEffectDuration are preserved when available. changeDescriptions is serialized from its map entries, while priorityLevel, timestamp, and updaters are copied into the frontend commit record.

FieldMeaning
durationMaximum actual render duration recorded for the commit
fiberActualDurationsPer-fiber actual durations
fiberSelfDurationsPer-fiber computed self durations
changeDescriptionsPer-fiber reasons describing what changed
updatersSerialized elements associated with the update
effectDurationOptional effect duration
passiveEffectDurationOptional passive-effect duration
priorityLevelPriority associated with the commit
timestampCommit time

These fields form each CommitDataBackend entry before the frontend normalizes array pairs into maps for lookup.

The backend also records the operations needed to rebuild the tree. flushPendingEvents deliberately keeps an empty operations update while profiling if commit metadata exists, because the operations and metadata arrays must remain aligned by commit index.

Each operations payload identifies its renderer and root, includes a string table, batches removals, appends pending tree operations, and can append Suspense suspender changes. This compact representation lets the frontend replay mutations without receiving a complete tree for every commit.

The frontend listens for operations, profilingData, and profilingStatus bridge events when ProfilerStore is constructed. After profiling, getProfilingData produces one backend payload containing commit data for each root.

Backend profiling flow — How does profiling data move from the renderer into the frontend model?

Evidence

The important boundary is that durations and reasons are stored as commit metadata, while tree shape is represented separately as an initial snapshot plus operations.

Sources: packages/react-devtools-shared/src/backend/fiber/renderer.js:7274-7285, packages/react-devtools-shared/src/backend/fiber/renderer.js:7288-7308, packages/react-devtools-shared/src/backend/types.js:196-211, packages/react-devtools-shared/src/devtools/views/Profiler/utils.js:125-148, packages/react-devtools-shared/src/backend/fiber/renderer.js:1440-1450, packages/react-devtools-shared/src/backend/fiber/renderer.js:1457-1474, packages/react-devtools-shared/src/backend/fiber/renderer.js:1480-1504, packages/react-devtools-shared/src/devtools/ProfilerStore.js:87-108, packages/react-devtools-shared/src/backend/fiber/renderer.js:7240-7324, packages/react-devtools-shared/src/devtools/ProfilerStore.js:25-380

How CommitTreeBuilder reconstructs commit N

getCommitTree first creates a cache list for the root and returns an existing entry when the requested commit index has already been built. It then validates that profiling data exists, finds the root’s operations, and rejects an index beyond the recorded commit count.

For the first commit, the builder creates a node map, initializes the tree from the stored snapshot with recursivelyInitializeTree, and applies the first operations array through updateTree. For every later commit, it takes the previous cached tree and applies the next operations array.

This is replay rather than mutation of one shared historical tree: each requested range is generated in order, and every generated CommitTree is pushed into the root’s cache. Consequently, selecting commit N can cause the builder to generate missing commits from the last cached index through N.

Commit tree replay — How does the frontend rebuild the tree at commit N?

Evidence

The reconstructed tree is then shared by both chart views: the flame graph requests getCommitTree followed by getFlamegraphChartData, while the ranked view requests getCommitTree followed by getRankedChartData.

Sources: packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js:62-88, packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js:90-123, packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js:90-125, packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraph.js:69-79, packages/react-devtools-shared/src/devtools/views/Profiler/CommitRanked.js:66-78

How raw data and derived data are separated

ProfilerStore keeps temporary backend data in _dataBackends until it can form _dataFrontend; the frontend object contains the information needed by the Profiler UI, including data that may be lazily parsed or derived through ProfilingCache.

ProfilerStore exposes the completed frontend model through profilingData, commit lookup through getCommitData, and root lookup through getDataForRoot. ProfilingCache uses the store to derive commit trees, fiber commit lists, flamegraph data, and ranked data.

The cache has separate invalidation paths for fiber commit lists, commit trees, flamegraph data, and ranked data. Calling invalidate clears the fiber list map and invokes all three derived-data invalidators.

When profiling is cleared or re-recorded, ProfilerStore.clear removes backend data, frontend data, snapshots, operations, and the renderer queue before invalidating the cache and emitting profilingData. This prevents charts and trees from using stale profiling state.

Sources: packages/react-devtools-shared/src/devtools/ProfilerStore.js:25-380, packages/react-devtools-shared/src/devtools/ProfilerStore.js:111-125, packages/react-devtools-shared/src/devtools/ProfilerStore.js:127-136, packages/react-devtools-shared/src/devtools/ProfilingCache.js:28-99, packages/react-devtools-shared/src/devtools/ProfilingCache.js:92-98, packages/react-devtools-shared/src/devtools/ProfilerStore.js:178-191

How it connects

The backend side belongs to the DevTools renderer integration and hands operations and profiling payloads across the bridge to the frontend ProfilerStore. The bridge protocol and its flat operations representation are described in DevTools Bridge Protocol.

The frontend views consume the store and cache to render the flame graph, ranked chart, commit selector, and updater details. Those UI responsibilities sit alongside the broader extension-to-panel connection described in React DevTools Extension.

Sources: packages/react-devtools-shared/src/devtools/ProfilerStore.js:99-108, packages/react-devtools-shared/src/backend/fiber/renderer.js:1457-1474, packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraph.js:69-79, packages/react-devtools-shared/src/devtools/views/Profiler/CommitRanked.js:66-78

Key takeaways

  • The backend records per-commit durations, change descriptions, updaters, priorities, timestamps, and optional effect durations.
  • Tree history is reconstructed from an initial snapshot plus one operations array per commit.
  • CommitTreeBuilder builds commit trees sequentially and caches them per root.
  • ProfilerStore holds raw and normalized profiling state; ProfilingCache owns derived trees and chart data.
  • Clearing or re-recording profiling data invalidates all derived cache layers.

Sources: packages/react-devtools-shared/src/backend/fiber/renderer.js:7240-7324, packages/react-devtools-shared/src/devtools/ProfilerStore.js:25-380, packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js:53-126, packages/react-devtools-shared/src/devtools/ProfilingCache.js:28-99, packages/react-devtools-shared/src/devtools/ProfilerStore.js:178-191, packages/react-devtools-shared/src/devtools/ProfilingCache.js:92-98

Want this for your repos?

Try Angada AI Wiki