Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Blazing Fast UI Development with Compose Hot Re...

Blazing Fast UI Development with Compose Hot Reload (droidcon Berlin 2025)

When working on UI, you want to see the results of your code changes as fast as possible. Waiting for apps to rebuild and relaunch, then getting the app to the desired state again only gets in your way.

Compose Hot Reload is a new JetBrains project that gives you live updates after code changes when running a Compose app on desktop - so you can see and feel how your app’s behaviour changes, without having to relaunch it at all. And you even get to keep your existing state!

In this talk, we’ll experience coding with Compose Hot Reload enabled with exciting live demos, and also learn a bit about how it all works under the hood.

If your project doesn’t have a desktop target yet… it might just be time to add one!

https://zsmb.co/talks/blazing-fast-compose-hot-reload/

Avatar for Márton Braun

Márton Braun

September 24, 2025
Tweet

More Decks by Márton Braun

Other Decks in Programming

Transcript

  1. Setup !// build.gradle.kts plugins { id("org.jetbrains.compose.hot-reload") version "1.0.0-beta08" } !//

    settings.gradle.kts plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" }
  2. Setup !// build.gradle.kts plugins { id("org.jetbrains.compose.hot-reload") version "1.0.0-beta08" } !//

    settings.gradle.kts plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } !// Default in Kotlin 2.2.0 composeCompiler { featureFlags.add(ComposeFeatureFlag.OptimizeNonSkippingGroups) }
  3. Setup !// build.gradle.kts plugins { id("org.jetbrains.compose.hot-reload") version "1.0.0-beta08" } !//

    settings.gradle.kts plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } !// Default in Kotlin 2.2.0 composeCompiler { featureFlags.add(ComposeFeatureFlag.OptimizeNonSkippingGroups) }
  4. Setup !// build.gradle.kts plugins { id("org.jetbrains.compose.hot-reload") version "1.0.0-beta08" } !//

    settings.gradle.kts plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } !// Default in Kotlin 2.2.0 composeCompiler { featureFlags.add(ComposeFeatureFlag.OptimizeNonSkippingGroups) }
  5. How does it work? Your app’s code JetBrains Runtime Hot

    Reload Agent Gradle Supervisor process
  6. How does it work? Supervisor process Your app’s code JetBrains

    Runtime Hot Reload Agent Dev Tooling IDE Recompiler
  7. How does it work? Supervisor process Your app’s code JetBrains

    Runtime Hot Reload Agent Dev Tooling IDE Recompiler
  8. How does it work? Supervisor process Your app’s code JetBrains

    Runtime Hot Reload Agent Dev Tooling IDE Recompiler DCEVM
  9. How does it work? Supervisor process Your app’s code JetBrains

    Runtime Hot Reload Agent Dev Tooling IDE Recompiler
  10. How does it work? Supervisor process Your app’s code JetBrains

    Runtime Hot Reload Agent Dev Tooling IDE Recompiler
  11. How does it work? Supervisor process Your app’s code JetBrains

    Runtime Hot Reload Agent Dev Tooling IDE Recompiler
  12. DCEVM class Offset( val x: Int, val y: Int, )

    Dynamic Code Evolution Virtual Machine Side Universe Class Loader class Offset( val x: Int, ) Current Class Loader
  13. DCEVM class Offset( val x: Int, val y: Int, )

    Dynamic Code Evolution Virtual Machine Current Class Loader
  14. DCEVM Dynamic Code Evolution Virtual Machine 42 Header 13 Header

    24 Header Offset@235235 Offset@534643 Offset@734122 Of class Offset( val x: Int, )
  15. DCEVM Dynamic Code Evolution Virtual Machine 42 Header 13 Header

    24 Header Offset@235235 Offset@534643 Offset@734122 Of class Offset( val x: Int, val y: Int, ) +
  16. DCEVM Dynamic Code Evolution Virtual Machine 42 Header 13 Header

    24 Header Offset@235235 Offset@534643 Offset@734122 Of Offset@235235 Offset@534643 Offset@734 class Offset( val x: Int, val y: Int, ) +
  17. DCEVM Dynamic Code Evolution Virtual Machine 42 Header 13 Header

    24 Header Offset@235235 Offset@534643 Offset@734122 Of Offset@235235 Offset@534643 Offset@734 42 Header 13 Header Head class Offset( val x: Int, val y: Int, ) +
  18. DCEVM Dynamic Code Evolution Virtual Machine 42 Header 13 Header

    24 Header Offset@235235 Offset@534643 Offset@734122 Of Offset@235235 Offset@534643 Offset@734 42 Header 13 Header Head 0 0 class Offset( val x: Int, val y: Int, ) +
  19. DCEVM Dynamic Code Evolution Virtual Machine Offset@235235 Offset@534643 Offset@734 42

    Header 13 Header Head 0 0 class Offset( val x: Int, val y: Int, ) +
  20. Compose diffing fun mediumPadding() = 16.dp @Composable fun Counter() {

    var counter by remember { mutableStateOf(0) } Text("Here's a counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } }
  21. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here's a counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  22. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here's a counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  23. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here's a counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  24. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here's a counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  25. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here’s a counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  26. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here’s a wonderful counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  27. fun mediumPadding() = 32.dp @Composable fun Counter() { var counter

    by remember { mutableStateOf(0) } Text("Here’s a wonderful counter:") Card { Button( modifier = Modifier.padding(mediumPadding()), onClick = { counter++ } ) { Text("Clicked $counter times") } } } Compose diffing
  28. zsmb.co/talks Márton Braun @zsmb.co Compose Hot Reload jb.gg/chr KotlinConf app

    jb.gg/kc-app Sebastian Sellmair’s content KotlinConf talk jb.gg/kc25-chr YouTube youtube.com/@s.sellmair Blog blog.sellmair.io Blazing Fast UI Development with