Compose Stability Analyzer 0.7.0: Recomposition Cascade and Live Heatmap

skydovesJaewoong Eum (skydoves)||5 min read

Compose Stability Analyzer 0.7.0: Recomposition Cascade and Live Heatmap

Jetpack Compose's stability system determines whether a composable function can be skipped during recomposition. When all parameters are stable, Compose can compare them and skip the function entirely if nothing changed. When even one parameter is unstable, the composable must re-execute every time its parent recomposes. Understanding which composables are stable and which are not is the first step toward optimizing Compose performance, but it's not the whole picture.

Compose Stability Analyzer has been providing real time stability analysis directly in Android Studio through gutter icons, hover tooltips, inline hints, and code inspections. These features answer the question "is this composable stable?" at a glance. Version 0.7.0 goes further by answering two additional questions that static analysis alone cannot address: "what happens downstream when this composable recomposes?" and "which composables are actually recomposing the most on a real device?"

In this article, you'll explore the two new features introduced in version 0.7.0: the Recomposition Cascade Visualizer and the Live Recomposition Heatmap.

Live Recomposition Heatmap

Static analysis tells you which composables could recompose unnecessarily. The Live Recomposition Heatmap tells you which ones actually are. It bridges runtime behavior with your IDE by reading @TraceRecomposition events from a connected device via ADB and displaying live recomposition counts directly above composable functions in the editor.

heatmap

To use the heatmap, you need the Compose Stability Analyzer Gradle plugin applied to your project, composable functions annotated with @TraceRecomposition, and logging enabled via ComposeStabilityAnalyzer.setEnabled(true) in your Application class. With those in place, open the Compose Stability Analyzer tool window and click the Start/Stop button in the title bar. If one device is connected, monitoring begins immediately. If multiple devices are connected, a picker popup lets you choose which one to monitor.

While the heatmap is running and you interact with your app, recomposition counts appear as color coded annotations above each composable in the editor. Green means fewer than 10 recompositions (normal frequency), yellow means 10 to 50 (worth investigating), and red means more than 50 (likely a performance issue). These thresholds are configurable in Settings > Tools > Compose Stability Analyzer.

Clicking any heatmap annotation opens the Heatmap tab in the tool window, pre-populated with detailed data for that composable: total recomposition count, recent events listed chronologically, and parameter changes for each event showing which parameters changed, which were stable, and which were unstable. This lets you go from a high level "this composable recomposed 47 times" observation directly to the specific parameter changes that triggered each recomposition, without searching through Logcat manually.

A clear button in the tool window title bar resets all accumulated data. This is useful when you restart your app or want to measure a specific interaction from a clean state.

Recomposition Cascade Visualizer

When a composable recomposes, it doesn't happen in isolation. The function re-executes, which means every child composable it calls also gets invoked. If those children have unstable parameters, they re-execute too, regardless of whether their inputs actually changed. A single unstable composable at the top of your screen can cascade through dozens of downstream functions, each one doing unnecessary work.

The Recomposition Cascade Visualizer makes this ripple effect visible. Right-click any @Composable function in the editor and select "Analyze Recomposition Cascade." The plugin traces the call tree from that function downward, building a tree of every composable that would be affected when the root recomposes.

cascade

Each node in the tree shows the composable name and its stability status: green for skippable (all parameters stable) and red for non-skippable (at least one unstable parameter). A summary at the top shows aggregate statistics: total downstream composables, how many are skippable, how many are not, and the maximum depth of the tree. This gives you a quick sense of the blast radius. A screen composable with 15 downstream functions and 8 of them non-skippable has a very different performance profile than one with 3 downstream functions that are all skippable.

The analyzer also handles recursive composable calls. If a tree rendering composable calls itself for child nodes, the cascade visualizer detects the cycle and marks it rather than entering an infinite loop. A configurable depth limit (default: 10 levels) keeps results manageable for deep hierarchies.

Double-clicking any node in the cascade tree navigates directly to that composable's source code. This makes the cascade view a practical starting point for performance work: find the non-skippable composables buried deep in your UI tree, jump to their source, and investigate what's making their parameters unstable.

Putting them together

The cascade visualizer and the heatmap are complementary. The cascade shows you the theoretical blast radius of a recomposition, the full tree of downstream composables that could be affected. The heatmap shows you the empirical reality, which composables are actually recomposing during real user interactions and how often.

A practical workflow looks like this: use gutter icons and the Stability Explorer to identify composables with unstable parameters. Run a cascade analysis on your screen level composables to understand the downstream impact. Then start the heatmap, interact with your app normally, and watch for red annotations. When you spot a hot composable, click its annotation to see the parameter change history. Fix the root cause (make properties val, use immutable collections, add @Stable annotations), clear the heatmap, and repeat your interactions. The counts should drop, confirming that your optimizations are working at runtime, not just in static analysis.

Both features are available in version 0.7.0 of the Compose Stability Analyzer IntelliJ plugin, which you can install from the JetBrains Marketplace or build from the repository.

As always, happy coding!

— Jaewoong