Compose 6 min read

Compose at Android Dev Summit 2026: The Performance Skill as a Code-Review Checklist

On Nov 4, 2026 the Android team published its Android Developer Summit Compose round-up. Most of the headline items are previews of things already in flight: the upcoming Compose 1.13 stable, Jetpack AppState in alpha, and Navigation 3 1.2 deep links. The part I think is underrated is smaller: a new Compose performance entry in the official Android skills repo, last updated 2026-10-22. It is written for coding agents, but it is also the most compact statement of Google's current Compose performance advice I have seen, and it reads well as a human code-review checklist.

4
Compose skills listed: Adaptive, Performance, XML-to-Compose, Ink
7
audit categories in the performance skill
1.13
upcoming Compose stable the post points to

Scope note: the blog post links to Summit session videos and does not publish API signatures or artifact versions for Compose 1.13. I only state what the post and the skill file say, and I have not invented version numbers.

What the round-up announced

The four Compose skills

The post lists what currently exists in the Android skills repo for Compose: an updated Adaptive skill (now adds foldable and desktop support, handling windowing, keyboard shortcuts, tooltips and trackpad hover states), a new Compose performance skill, an XML to Compose migration skill, and a new Ink skill. If skills are new to you, my Android Skills post explains the model.

The performance skill, read as a checklist

The skill starts with prerequisites that no amount of code review can replace: profile release builds only (debuggable builds degrade ART performance), keep R8 minification on, and generate baseline profiles for critical journeys such as cold start and key scrolling feeds. Then it audits seven categories. These are the rules I would put in a PR template.

1. State: defer reads, derive cheaply

Defer state reads to the layout or draw phase by passing lambdas, so a fast-changing value does not recompose its parent. The skill also says to prefer computedStateOf on Compose 1.13+ for fast-changing simple conditions, and derivedStateOf for heavier calculations.

// Reads scroll offset during composition: recomposes on every frame
@Composable
fun Header(scroll: ScrollState) {
    val alpha = 1f - (scroll.value / 300f).coerceIn(0f, 1f)
    Box(Modifier.alpha(alpha)) { /* ... */ }
}

// Reads it in the draw phase: no recomposition
@Composable
fun Header(scroll: ScrollState) {
    Box(
        Modifier.graphicsLayer {
            alpha = 1f - (scroll.value / 300f).coerceIn(0f, 1f)
        }
    ) { /* ... */ }
}

On stability, the guidance is deliberately restrained: Strong Skipping Mode already handles most cases, so do not sprinkle @Stable, @Immutable or ImmutableList over collection models. Focus on making composables cheap rather than maximizing skips.

2. Layouts and measurement

Avoid onGloballyPositioned; use onVisibilityChanged, onPlaced, onLayoutRectChanged or requireLayoutCoordinates(). Anchor floating content with a custom Layout rather than coordinates stored in state, use the lambda form of Modifier.offset, and keep BoxWithConstraints and SubcomposeLayout out of hot paths.

3. Lazy layouts

Always provide primitive key and contentType, replace indexOf lookups with itemsIndexed, use a Set for selection state, resolve CompositionLocals in the parent, and collect shared flows once in the parent instead of per item. Do not fire analytics from pre-fetched items; use visibility-based tracking.

LazyColumn {
    itemsIndexed(
        items = messages,
        key = { _, m -> m.id },
        contentType = { _, m -> m.kind }
    ) { index, message ->
        MessageRow(
            message = message,
            selected = message.id in selectedIds,
            onClick = { onSelect(message.id) }
        )
    }
}

4. Animation and shared transitions

Read animated alpha, scale, rotation and color inside graphicsLayer; use offset {}, layout {} or animateBounds for position and size; attach shared transitions only when the item is visible.

5. Effects and threading

No side effects in the composable body. Do not use LaunchedEffect for synchronous work, and do not leave an empty onDispose in a DisposableEffect. Use collectAsStateWithLifecycle() for UI flows, rememberUpdatedState for stale captures, and replace Handler.postDelayed or TimerTask with LaunchedEffect plus delay().

6. Graphics and custom drawing

Replace decorative Canvas nodes with drawWithCache so paths, paints and brushes are built once. Remember RuntimeShader and ShaderBrush, prefer Path.rewind() over reset() in hot loops, and avoid Pair, Triple and HashSet<Long> in drawing code in favor of MutableLongSet.

fun Modifier.badgeBackground(color: Color) = this.drawWithCache {
    val path = Path().apply {
        addRoundRect(RoundRect(size.toRect(), CornerRadius(12.dp.toPx())))
    }
    onDrawBehind { drawPath(path, color) }
}

7. Custom modifiers

Migrate legacy Modifier.composed to ModifierNodeElement plus Modifier.Node (or DelegatingNode when delegating), using capability interfaces such as DrawModifierNode and LayoutModifierNode. Query requireLayoutCoordinates() on demand instead of implementing GlobalPositionAwareModifierNode.

private data class CircleElement(val color: Color) : ModifierNodeElement<CircleNode>() {
    override fun create() = CircleNode(color)
    override fun update(node: CircleNode) { node.color = color }
}

private class CircleNode(var color: Color) : Modifier.Node(), DrawModifierNode {
    override fun ContentDrawScope.draw() {
        drawCircle(color)
        drawContent()
    }
}

fun Modifier.circle(color: Color) = this then CircleElement(color)

The sample code above follows the patterns the skill describes; the skill file itself only paraphrases the modifier example, so treat my snippets as illustrations and check them against your Compose version.

Why it matters beyond agents

Two things stand out. First, the skill tells an agent to read a per-category reference file before flagging or editing anything, which is exactly how a good reviewer should work: know the approved fix and its scope limits before commenting. Second, the guidance is notably anti-cargo-cult. No blanket stability annotations, no wrapping everything in remember, and a plain getter for trivial values. If you inherited a codebase full of defensive annotations, that is a useful permission slip to simplify.

What I would do this week

Sources: the Android Developers Blog post "Build for every screen with the latest Jetpack Compose updates from Android Developer Summit" (Nov 4, 2026) and the jetpack-compose-performance SKILL.md in the android/skills repository, both retrieved Nov 8, 2026.

Comments 0

No comments yet. Be the first to leave one!

Leave a comment