Why are data classes from my library module treated as unstable by the Compose compiler?
0 reputation · 19 Jan 2022, 07:49 UTC
0 reputation · 19 Jan 2022, 07:49 UTC
I have a multi-module Android project using Jetpack Compose (compiler 1.5.x, Kotlin 1.9). UI state is modeled as plain Kotlin data classes in a shared :core:model module, and composables in :feature modules consume them. The generated Compose compiler reports show these data classes classified as unstable, even though they contain only val properties of primitive and String types. Identical classes declared inside the app module are inferred as stable.
My understanding is that stability inference does not cross module boundaries for non-annotated types, so consumers must treat external classes as unstable. This forces recomposition of every composable that takes these models as parameters, and I would rather not annotate shared model classes with Compose-specific annotations like @Stable or @Immutable, since the model module has no Compose dependency.
Is there a supported way to make the compiler treat classes from another module as stable without adding a Compose dependency to that module — for example, a stability configuration file, and is that mechanism officially documented and safe to rely on across compiler upgrades?
Alternatively, is wrapping the models in stable types at the feature-module boundary the recommended pattern, and does it carry meaningful runtime or maintenance overhead compared to annotating the models directly?
The Compose compiler only treats a type as stable if it is defined in the same Gradle module that is compiling the composables, or if the type is explicitly annotated with @Stable or @Immutable. Data classes that live in a separate module (e.g. :core:model) are therefore inferred as unstable by default, even if they contain only immutable val properties. There is no official stability‑configuration file that can be added to a library module to change this behaviour without adding a Compose dependency.
@Stable or @Immutable on its classes, so they default to unstable.When the library can depend on androidx.compose.runtime:runtime, add @Stable (or @Immutable if the class is truly immutable) to the data class. The compiler will then treat the type as stable across modules.
data class UserUiModel(val user: com.example.model.User) @Stable
There is no stability configuration file or plugin that can declare external types as stable without adding Compose annotations or a wrapper. This behaviour is documented in the Compose compiler release notes and is expected to remain consistent across future releases.
To ensure the chosen solution works, confirm that the library module is compiled with the same Kotlin version (1.9) as the app. Mismatched Kotlin versions can affect stability inference. If you can add a Compose runtime dependency to the library, try annotating the data class directly; otherwise, implement the wrapper in the feature module.
Compose treats cross‑module data classes as unstable unless they are annotated or wrapped. The only supported ways are to add @Stable/@Immutable in the library (requiring a Compose dependency) or to create a stable wrapper in the consuming module. Neither approach introduces meaningful runtime overhead, and the wrapper keeps Compose concerns isolated from the domain layer.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.