Lesson 5

Replace, movable, and reusable groups

Distinguish control-flow replacement, state-preserving movement, and node reuse in the runtime protocol.

3 min readUpdated Jul 11, 2026

Status: The three roles—replace a control-flow region, move keyed content, and reuse content or nodes—are Durable protocol distinctions. Their method names and lifecycle details are Version-specific at the pinned revision.

Outcome

When you see a group call, ask what kind of continuity it promises:

GroupContinuity question
ReplaceCan this region only be inserted, removed, or replaced?
MovableCan this keyed content move to another position while keeping identity?
ReusableCan existing content or nodes be prepared for a different data key?

They solve different reconciliation problems.

Replace: control flow, not movement

An if branch has a fixed logical location, but its selected content can change. startReplaceGroup(key) and endReplaceGroup() mark it as non-movable replacement work.

The current Composer.kt retains startReplaceableGroup for older compiler output while newer compilers use startReplaceGroup.

Movable: identity follows a data key

A movable group adds a data key to a compiler source key:

@Composable
fun Item(id: String) {
    key(id) {
        remember { expensiveObject(id) }
        Content(id)
    }
}

The compiler key describes source location. The data key describes which item occupies it. startMovableGroup(key, dataKey) lets tested keyed content move with its key.

id is not globally unique; it must distinguish relevant siblings in the local parent context. Duplicate local keys leave matching ambiguous.

Diagram
flowchart LR
    SourceKey[Compiler source key] --> Pair[Group identity pair]
    DataKey[Item data key] --> Pair
    Pair --> Same[Same item at new position]
    Pair --> Move[Move content and identity]
    ReplaceKey[Branch key only] --> Replace[Replace region]
    ReuseKey[Reuse data key] --> Reuse[Prepare existing content]

The visual shows roles, not a slot-table address format. Storage is Chapter 3. MovableContentTests.kt includes movableContentPreservesNodes and remembered-value move tests. They support a bounded claim about the tested path, not every structural edit.

Reusable: prepare for a different occupant

ReusableContent(key) { ... } calls startReusableGroup with a reuse key. When that key changes, the runtime can enter a reusing state: cache values may be invalid and changed checks can report differences until a reusable node is reached.

Reusable content therefore refreshes a reusable shape; it does not promise that every remembered value follows a new item. CompositionReusingTests.kt tests reuse, deactivation, and release callbacks.

Experiment: reorder, then change the reuse key

Build a test composition with keyed items and one reusable region. Compose A, B, then recompose B, A, recording remembered-token and node identity. Change a ReusableContent key from A to C and record callbacks and recalculation.

Control: remove key(id). Expected: the keyed path can match by data key; the unkeyed path has only position. Limit: callback names and node operations are tied to the cited tests.

Misconceptions

  • “Movable and reusable mean the same thing.” Movable preserves identity across position; reusable refreshes an occupant.
  • “Replace groups can move when keys match.” They are non-moving control-flow boundaries.
  • “A data key is enough.” Identity also uses source context and local position.
  • “Reusable content preserves every remember value.” Reuse includes invalidation and refresh.

Check yourself

A list item moves from index 0 to index 1 but keeps the same stable ID. Which group role expresses that continuity? A view-holder-like node is then reused for a different ID. Which role expresses that change, and why is it not the same promise?

Evidence notes

ClaimDirect evidenceStatus
Replace groups are non-moving insert/remove/replace regionsComposer.kt, startReplaceGroupDurable Version-specific
Movable groups pair a compiler key with a data key so keyed content can moveComposer.kt, startMovableGroup, and MovableContentTests.ktDurable Version-specific
Reusable groups change composer behavior when their reuse key changesComposer.kt, startReusableGroup, and CompositionReusingTests.ktVersion-specific
Current source retains an older replaceable method for generated-code compatibilityComposer.kt and Compose Compiler 1.5.11 release notesVersion-specific

Freshness

Refresh this lesson when the Composer group contracts, ReusableContent, movable-content tests, or compiler compatibility fallbacks change. Re-run the reorder/reuse experiment against the new pinned runtime before making a stronger lifecycle claim.

Finished this lesson?

Your progress stays only in this browser.