remember vs rememberSaveable in Jetpack Compose 🤔
If you've ever built a screen in Jetpack Compose and wondered why your state resets on rotation or process death, you've probably hit the remember vs rememberSaveable confusion. Let's break it down.
remember 🧠
Stores state only in memory.
Survives recompositions.
BUT… lost on configuration changes (rotation, dark mode toggle) or process death.
var text by remember { mutableStateOf("") }👉 Good for ephemeral UI state (scroll position, animations, toggles).
rememberSaveable 💾
Stores state in memory + Bundle (or custom saver).
Survives recompositions and config changes.
Restores automatically after process death.
var text by rememberSaveable { mutableStateOf("") }👉 Use for user inputs (form fields, text, selections) that should persist across rotations.
When rememberSaveable Fails
Custom objects need custom savers:
// ❌ This won't work - custom objects need custom savers
data class User(val name: String, val age: Int)
var user by rememberSaveable { mutableStateOf(User("", 0)) } // Crashes!
// ✅ This works - with custom saver
var user by rememberSaveable(
saver = Saver(
save = { mapOf("name" to it.name, "age" to it.age) },
restore = { User(it["name"] as String, it["age"] as Int) }
)
) { mutableStateOf(User("", 0)) }Performance Consideration
rememberSaveable has slight overhead since it serializes to Bundle, so don't use it for frequently changing states like animation values.
Quick Decision Tree
- Text input, form data, user selections →
rememberSaveable - Animation states, scroll positions, temporary UI flags →
remember - Custom objects →
remember+ manual save/restore OR custom saver
Real-World Examples
Form Input (Use rememberSaveable)
@Composable
fun LoginForm() {
var email by rememberSaveable { mutableStateOf("") }
var password by rememberSaveable { mutableStateOf("") }
Column {
TextField(
value = email,
onValueChange = { email = it },
label = { Text("Email") }
)
TextField(
value = password,
onValueChange = { password = it },
label = { Text("Password") }
)
}
}Animation State (Use remember)
@Composable
fun AnimatedButton() {
var isPressed by remember { mutableStateOf(false) }
val scale by animateFloatAsState(
targetValue = if (isPressed) 0.9f else 1f
)
Button(
modifier = Modifier
.scale(scale)
.pointerInput(Unit) {
detectTapGestures(
onPress = {
isPressed = true
tryAwaitRelease()
isPressed = false
}
)
},
onClick = { }
) {
Text("Press me")
}
}TL;DR ⚡
Use remember for short-lived UI states.
Use rememberSaveable when the state matters across rotations or process death.
Think of it like this:
🧠 remember = memory only
💾 rememberSaveable = memory + save/restore
Wrapping Up
The key is understanding the lifecycle of your state and choosing the right tool for the job. When in doubt, ask yourself: "Would my users be frustrated if this state disappeared after a rotation?" If yes, use rememberSaveable.
What state management patterns have you found most useful in Compose? Share your experiences!