These are some of the common Jetpack Compose mistakes that you need to avoid that lay performance, break UI and annoy users. Find out the things the most experienced Android developers wished they knew.

As someone who has reviewed hundreds of Jetpack Compose codebases in the last two years, nay, the same mistakes come up time and time, which motes me to write this post. Even seasoned Android developers who are used to traditional View systems get caught by these when moving to Compose.

The worst part? Top of the list is: a lot of these problems you do not notice until your app gets into production with real users and an array of different devices.

“Samsung Galaxy S25 Ultra showing Jetpack Compose app with red ‘MISTAKES’ text and Compose logo”

1. Calling Functions Inside Composables

This is the single biggest performance killer I see in Compose apps:

@Composable
fun UserProfile(userId: String) {
    val userData = fetchUserData(userId) // DON'T DO THIS
    
    Text(text = userData.name)
}

Notice that function call triggers every recomposition. Always use LaunchedEffect or remember with appropriate keys.

@Composable
fun UserProfile(userId: String) {
    var userData by remember { mutableStateOf<User?>(null) }
    
    LaunchedEffect(userId) {
        userData = fetchUserData(userId)
    }
    
    userData?.let { user ->
        Text(text = user.name)
    }
}

2. Ignoring Composition Locals

Developers end up creating prop drilling nightmare rather than use CompositionLocal for theme data, user preferences or dependency injection.

// Instead of passing theme through 5 levels of composables
val LocalAppTheme = compositionLocalOf { AppTheme() }

@Composable
fun MyApp() {
    CompositionLocalProvider(LocalAppTheme provides currentTheme) {
        MainScreen()
    }
}

3. Overusing State Hoisting

Not all state should exist at the top level. If something is a local UI state, e.g. expanded/collapsed states, focus, or animations, keep it in the component it is used.

@Composable
fun ExpandableCard() {
    // This state doesn't need to be hoisted
    var isExpanded by remember { mutableStateOf(false) }
    
    Card(
        modifier = Modifier.clickable { isExpanded = !isExpanded }
    ) {
        // Card content
    }
}

4. Misunderstanding remember() Keys

Remembering without keys causes stale data and confounding behavior:

@Composable
fun ProductList(products: List<Product>) {
    // Wrong: remembers first products list forever
    val processedProducts = remember { processProducts(products) }
    
    // Right: recomputes when products change
    val processedProducts = remember(products) { processProducts(products) }
}

5. Creating Objects in Composable Body

This leads to a waste of work, as each recomposition creates new objects like:

@Composable
fun AnimatedIcon() {
    // Creates new AnimationSpec every recomposition
    val animationSpec = tween<Float>(durationMillis = 300)
    
    // Better: remember expensive objects
    val animationSpec = remember { tween<Float>(durationMillis = 300) }
}

6. Ignoring Modifier Order

The order of modifers is very important as it could layout and speed. First background, then padding, then clickable, then size constraints

// Wrong order - padding affects clickable area
Modifier
    .padding(16.dp)
    .clickable { }
    .background(Color.Blue)

// Correct order
Modifier
    .clickable { }
    .background(Color.Blue)
    .padding(16.dp)

7. Not Using derivedStateOf

Extract derived state using derivedStateOf when state depends on other state to avoid needless recomposition:

@Composable
fun FilteredList(items: List<Item>, query: String) {
    // Recomputes on every recomposition
    val filteredItems = items.filter { it.name.contains(query) }
    
    // Better: only recomputes when dependencies change
    val filteredItems by remember {
        derivedStateOf { items.filter { it.name.contains(query) } }
    }
}

8. Blocking the Composition Thread

And Compose is being executed on the main thread. Heavy computations when composing freezes your UI:

@Composable
fun ExpensiveCalculation(data: List<Int>) {
    // Blocks composition
    val result = data.map { heavyComputation(it) }
    
    // Better: move to background
    var result by remember { mutableStateOf<List<Int>>(emptyList()) }
    
    LaunchedEffect(data) {
        result = withContext(Dispatchers.Default) {
            data.map { heavyComputation(it) }
        }
    }
}

9. Improper Side Effect Management

Side effect APIs used incorrectly → Memory leaks and crashes

  • LaunchedEffect: For suspend functions
  • DisposableEffect: For cleanup (listeners, observers)
  • SideEffect: For non-Compose APIs that require the latest values
@Composable
fun LocationTracker() {
    DisposableEffect(Unit) {
        val locationListener = createLocationListener()
        locationManager.requestLocationUpdates(locationListener)
        
        onDispose {
            locationManager.removeUpdates(locationListener)
        }
    }
}

10. Not Testing Recomposition Behavior

Compose UIs are tested like plain old Views, causing bugs related to recomposition to go undetected by many developers. Use composition testing tools:

@Test
fun testRecompositionBehavior() {
    var recompositionCount = 0
    
    composeTestRule.setContent {
        RecompositionCounter { recompositionCount++ }
        MyComposable()
    }
    
    // Assert recomposition count expectations
}

The Road to Compose Mastery

The Android team at google has stated those apps that follow these practices experience 40 percent fewer performance issues and much higher user experience scores.

The key insight? Jetpack Compose is less of a new UI toolkit and more of a new paradigm, and with that comes the requirement of unlearning some of our old Android development habits.

Use that as a starting point to audit your current Compose code for these types of problems. Take the time to rectify each error singularly and leverage the composition debugging tools in Android Studio to confirm that you are addressing the issues.

Developers who nail concepts such as this early on will build together the fluid performant Android apps users love and competitors cannot begin to create.