
Compose strong skipping은 recomposition을 전부 없애주는 마법 같은 옵션이 아닙니다.
오히려 정확한 이해가 필요합니다. 어떤 composable을 건너뛸 수 있는지 판단하는 기준이 넓어지고, unstable parameter를 가진 composable도 skip 대상이 될 수 있습니다.
그래서 이 기능을 이해하려면 “recomposition이 나쁜가?”가 아니라 “언제 다시 실행해야 하고, 언제 건너뛰어도 되는가?”를 봐야 합니다.
Compose strong skipping을 한 줄로 정리하기

Android 공식 문서 기준으로 strong skipping은 Kotlin 2.0.20에서 기본 활성화됩니다. strong skipping이 켜지면 모든 restartable composable function이 skippable이 될 수 있습니다.
중요한 점은 unstable parameter가 있어도 무조건 다시 그린다는 식의 단순한 이해가 더 이상 맞지 않을 수 있다는 것입니다.
recomposition과 skipping은 다른 말이다
recomposition은 상태 변화에 따라 composable을 다시 실행해 UI를 최신 상태로 맞추는 과정입니다. Compose가 선언형 UI인 이상 recomposition 자체는 자연스러운 동작입니다.
skipping은 Compose가 어떤 composable을 다시 실행하지 않아도 된다고 판단해 건너뛰는 최적화입니다. 즉 목표는 recomposition을 무조건 줄이는 것이 아니라, 필요 없는 recomposition을 피하는 것입니다.
이 차이를 놓치면 remember를 과하게 쓰거나, 안정성 경고를 없애는 데만 집중하면서 실제 UI 상태 설계를 망칠 수 있습니다.
stable과 unstable 비교 기준이 중요하다
공식 문서 설명에 따르면 strong skipping에서는 stable parameter와 unstable parameter의 비교 방식이 다릅니다. stable parameter는 Object.equals() 기준으로 비교되고, unstable parameter는 instance equality, 즉 === 기준으로 비교됩니다.
이 차이는 실무에서 중요합니다. 같은 값을 담고 있어도 매번 새 인스턴스를 만들면 unstable parameter는 달라진 것으로 볼 수 있습니다.
data class UiItem(
val id: Long,
val title: String
)
@Composable
fun ItemRow(item: UiItem, onClick: () -> Unit) {
Text(item.title)
}위 코드에서 핵심은 data class를 썼다는 사실만이 아닙니다. 상위 계층에서 item과 onClick을 매번 새로 만드는지, 상태가 어디서 변하는지, list key를 안정적으로 주는지가 함께 영향을 줍니다.
lambda 자동 remember를 오해하면 안 된다
strong skipping에서는 composable 내부 lambda가 자동으로 remember될 수 있습니다. unstable capture가 있는 lambda도 포함될 수 있다는 점이 공식 문서의 중요한 변화입니다.
하지만 이 말이 모든 lambda 관련 성능 고민이 사라졌다는 뜻은 아닙니다. lambda가 어떤 상태를 캡처하는지, 그 상태가 언제 바뀌는지, 하위 composable에 어떤 의미로 전달되는지는 여전히 코드 설계의 문제입니다.
특정 lambda를 memoize하지 않아야 한다면 @DontMemoize를 사용할 수 있고, composable 자체를 skip 대상에서 빼야 한다면 @NonSkippableComposable을 검토할 수 있습니다.
remember 남용보다 상태 흐름을 먼저 봐야 한다
Compose 성능 문제가 보이면 remember를 더 붙이는 방식으로 대응하기 쉽습니다. 하지만 strong skipping 이후에는 더더욱 상태 흐름을 먼저 봐야 합니다.
- UI state가 너무 큰 객체 하나로 묶여 있지 않은가
- 리스트 item key가 안정적인가
- 상위 composable에서 매번 새 collection을 만들고 있지 않은가
- derivedStateOf가 필요한 계산과 불필요한 계산을 구분했는가
- 실제 병목을 Layout Inspector, tracing, compiler report로 확인했는가
성능 최적화는 느낌으로 하면 안 됩니다. recomposition 횟수만 보고 결론을 내리기보다, 실제 frame drop, measure/layout 비용, list item 재사용 문제까지 같이 봐야 합니다.
도입할 때의 실무 기준
Kotlin 2.0.20 이후 프로젝트라면 strong skipping이 기본값이라는 사실을 먼저 인지해야 합니다. 예전 기준으로 작성된 Compose 성능 글이나 팀 규칙이 그대로 맞지 않을 수 있습니다.
그렇다고 기존 코드를 급하게 바꿀 필요는 없습니다. 안정성 모델, state holder 구조, list rendering, lambda 전달 방식을 점검하고, 성능 문제가 있는 화면부터 측정하는 편이 좋습니다.
- Compose compiler와 Kotlin 버전을 확인한다
- 성능 문제가 있는 화면을 먼저 정한다
- recomposition count와 실제 frame 성능을 함께 본다
- stable/unstable 모델 경고를 무조건 제거 대상이 아니라 설계 신호로 본다
- opt-out annotation은 이유를 코드 리뷰에 남긴다
정리
Compose strong skipping은 Compose 성능 모델을 더 현실적으로 만들어주는 변화입니다. unstable parameter가 있다고 해서 무조건 다시 실행해야 한다는 단순한 모델에서 벗어나게 합니다.
하지만 최적화의 책임이 사라지는 것은 아닙니다. state를 작게 나누고, 불필요한 객체 생성을 줄이고, 실제 성능을 측정하는 기본기는 그대로 중요합니다.
관련해서는 stateIn과 shareIn은 언제 써야 할까, callbackFlow는 언제 써야 할까도 함께 보면 좋습니다.
출처: Android Developers – Strong skipping mode, Android Developers – Stability in Compose