
When building with Jetpack Compose, choosing how to pass data down the UI tree is a critical architectural decision.
In this post, we compare three common approaches: Static Objects, Dynamic Locals, and Static Locals.
🧑🏻💻 1. Quick Comparison Table

🧑🏻💻 2. Full Implementation: All-in-One File Example
Defining your CompositionLocal at the Top-level (outside of any function or class) is the golden rule of Compose.
This makes the "Key" globally accessible and permanent.
🧑🏻💻 3. Why use a "Top-level val"?
Why outside the function?:
A CompositionLocal is a unique Key. If defined inside a function, a new key is generated every time that function recomposes.
This breaks the link between the Provider and the .current call, resulting in data not being found.
Why val?:
The Local... itself is just a definition of a "conduit." You don't need to change the conduit itself (var).
Changing the data inside the conduit is handled by the CompositionLocalProvider.
🧑🏻💻 Final Conclusion
- object: Use for fixed values that don't need to be swapped for tests or previews.
- compositionLocalOf: Use for dynamic states where you want to minimize recomposition overhead.
- staticCompositionLocalOf: Use for infrastructure/themes where read speed is the priority.
By keeping your definitions at the top-level of your files, your Compose architecture will remain clean, predictable, and performant.
Related Categories : Android・AndroidStudio・dagger・JetpackCompose・Kotlin・Terrible・Terrible