compose-performance
Skill0 starsChanged 32 days agoMITView on GitHub
Jetpack Compose performance discipline: stability, recomposition control, deferred state reads, and baseline profiles. Use when writing or reviewing Compose UI code, diagnosing recomposition storms, or preparing release builds. Every rule has a machine check in checks/.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- chrisbanes/skillstheir own version, first seen Jun 18, 2026
- thetruong1099/android-mvi-base-codetheir own version, first seen Mar 18, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- chrisbanes/skills★ 1.1ksame name
- thetruong1099/android-mvi-base-code★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository11 other files it gives its agents.
- android-testingSkill
- compose-architectureSkill
- compose-migrationSkill
- compose-multiplatformSkill
- compose-testingSkill
- dependency-injectionSkill
- gradle-build-logicSkill
- kmp-fundamentalsSkill
- material3-themingSkill
- offline-firstSkill
- release-engineeringSkill
The file
We split this skill into the rules it gives an agent
10 rules. About 0 are common, 4 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 14
After ANY Compose UI edit, run the Verification step (bottom of this file).
- Very specific: line 18
MUST make UI-state data classes fully immutable (val only) and annotate them @Immutable when they are passed as composable parameters.
- Very specific: line 36
MUST NOT pass MutableList / MutableMap / MutableSet as composable parameters.
- Very specific: line 52
MUST NOT create mutable collections inside remember when the value only feeds the UI.
- Distinctive: line 68
MUST defer state reads to the lambda of the modifier or component that needs them, so a changing value skips the parent recomposition.
- Very specific: line 82
MUST use derivedStateOf when computing a value from state where only the computed result matters (e.g.
- Very specific: line 97
MUST provide a stable, unique key for every items(...) entry whose content or identity changes independently of position.
- Very specific: line 112
MUST include a baseline profile for release builds: either a src/main/baseline-prof.txt or the androidx.baselineprofile Gradle plugin wired …
- Distinctive: line 121
Run after every Compose-related edit (from the project root):
- Distinctive: line 129
All three must pass (exit 0) before declaring the task done.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Compose Performance
Operational rules for a coding agent. RIGHT/WRONG pairs are canonical. After ANY Compose UI edit, run the Verification step (bottom of this file).
1. Stability
MUST make UI-state data classes fully immutable (val only) and annotate
them @Immutable when they are passed as composable parameters.
WRONG:
data class UserUi(val name: String, var selected: Boolean)RIGHT:
@Immutable
data class UserUi(val name: String, val selected: Boolean)WHY: a single var property makes the class unstable. Every unstable
parameter defeats skipping for every composable that receives it, so one
mutable field can undo recomposition optimization across a whole screen.
MUST NOT pass MutableList / MutableMap / MutableSet as composable
parameters. Use kotlinx.collections.immutable types (ImmutableList,
ImmutableMap) or @Immutable wrappers.
WRONG:
@Composable
fun Feed(items: MutableList<String>) { ... }RIGHT:
@Composable
fun Feed(items: ImmutableList<String>) { ... }MUST NOT create mutable collections inside remember when the value only
feeds the UI. Prefer state-holder classes with immutable snapshots.
WRONG:
val history = remember { mutableListOf<Int>() }RIGHT:
var history by remember { mutableStateOf(immutableListOf<Int>()) }
// or keep mutation inside a @Stable state-holder that exposes ImmutableList2. Deferred state reads
MUST defer state reads to the lambda of the modifier or component that needs them, so a changing value skips the parent recomposition.
WRONG:
val offset = scrollState.value
Row(modifier = Modifier.offset(x = offset.dp)) { Header() }RIGHT:
Row(modifier = Modifier.offset { IntOffset(scrollState.value, 0) }) { Header() }MUST use derivedStateOf when computing a value from state where only the
computed result matters (e.g. "show scroll-to-top button when scrolled").
WRONG:
val showButton = scrollState.value > 0 // recomposes on every pixelRIGHT:
val showButton by remember { derivedStateOf { scrollState.value > 0 } }3. Lazy lists
MUST provide a stable, unique key for every items(...) entry whose
content or identity changes independently of position.
WRONG:
LazyColumn { items(messages) { msg -> MessageRow(msg) } }RIGHT:
LazyColumn { items(messages, key = { it.id }) { msg -> MessageRow(msg) } }4. Baseline profiles
MUST include a baseline profile for release builds: either a
src/main/baseline-prof.txt or the androidx.baselineprofile Gradle
plugin wired to a macrobenchmark module.
Startup and first-frame jank are dominated by JIT; a baseline profile is the single highest-leverage release setting.
Verification
Run after every Compose-related edit (from the project root):
bash <skill-dir>/checks/check_no_var_in_ui_state.sh <src-dir>
bash <skill-dir>/checks/check_immutable_collections.sh <src-dir>
bash <skill-dir>/checks/check_baseline_profile.sh <project-root>All three must pass (exit 0) before declaring the task done. Checks are deterministic static heuristics — they catch the documented anti-patterns above, not every perf bug. For deep verification use the Compose compiler metrics report and a macrobenchmark, per references/stability.md.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

