The Problem
Using var
in Kotlin data class constructors causes performance issues in Jetpack Compose apps.
Bad:
data class UserProfile(
val id: String,
val name: String,
var isMarried: Boolean // This breaks Compose optimization
)
Good:
data class UserProfile(
val id: String,
val name: String,
val isMarried: Boolean // Immutable = optimized
)
What Happens Under the Hood
Compose Stability Analysis
- Compose compiler analyzes classes at build time
- Classes with
var
properties = marked as “unstable” - Unstable classes = unnecessary recompositions
- More recompositions = worse performance
The Impact
// With var: UserProfile is UNSTABLE
data class UserProfile(var isMarried: Boolean)
// Result: Every UI update triggers recomposition
// Even when UserProfile data didn't change
Real Performance Difference
Before (with var):
- UserProfile: UNSTABLE
- UI recomposes on every state change
- Layout Inspector shows constant recomposition counts
After (with val):
- UserProfile: STABLE
- Compose skips unnecessary recompositions
- Layout Inspector shows optimized rendering
How to Check Performance
Enable Compose compiler metrics in gradle.properties
:
androidx.enableComposeCompilerMetrics=true
androidx.enableComposeCompilerReports=true
Check generated reports in app/build/compose_compiler/
:
*-classes.txt
→ stability information*-composables.txt
→ recomposition behavior
Why This Matters
Performance Impact
- Unnecessary recompositions slow down the app
- Especially noticeable in complex UIs
- Affects battery life and user experience
Compose Optimization Strategy
Compose uses two mechanisms:
- Compile-time stability analysis → determines if class is stable
- Runtime reference equality → compares object instances
Stable classes enable both optimizations.
The Fix
Instead of mutable constructor properties:
// Don't do this
data class User(var name: String)
Use immutable properties:
// Do this
data class User(val name: String)
For mutable state, use external state management:
// In ViewModel or Composable
var userName by mutableStateOf("")
val user = User(name = userName)
Key Takeaways
var
in data class constructors = performance penalty in Composeval
properties = stable classes = better performance- Use Compose compiler metrics to verify optimizations
- Keep UI models immutable for predictable behavior
- Move mutable state outside data class constructors
Simple Rule
Data classes for UI models should only use val
properties.
This ensures optimal Compose performance and prevents hard-to-debug recomposition issues.
Related Articles
- Jetpack Compose: Architecture - Understanding the layered architecture of Jetpack Compose
- Jetpack Compose: Composition Phase - Deep dive into UI rendering and state management
- Understanding compositionLocalOf vs. staticCompositionLocalOf - Choosing the right CompositionLocal for better performance