Skip to main content
The Runtime API provides composable functions and properties for interacting with hot reload from within Compose UI code.

isHotReloadActive

A property that returns true if the application was started with hot reload enabled.
public expect val isHotReloadActive: Boolean
isHotReloadActive
Boolean
true if hot reload is active, false otherwise

Usage

Use this property to conditionally enable development-only features:
import org.jetbrains.compose.reload.isHotReloadActive

fun main() {
    if (isHotReloadActive) {
        println("Development mode: Hot reload is enabled")
        enableDebugLogging()
    }
    
    application {
        // Your app
    }
}

Platform Behavior

  • JVM/Desktop: Returns true if the system property compose.reload.isActive equals "true"
  • Other platforms: Always returns false

Common Use Cases

import androidx.compose.runtime.Composable
import org.jetbrains.compose.reload.isHotReloadActive

@Composable
fun App() {
    // Show development tools only during hot reload
    if (isHotReloadActive) {
        DevelopmentToolbar()
    }
    
    MainContent()
}

// Adjust logging level
fun configureLogging() {
    val level = if (isHotReloadActive) LogLevel.DEBUG else LogLevel.INFO
    Logger.setLevel(level)
}

// Enable expensive validation checks
fun validateState() {
    if (isHotReloadActive) {
        performExpensiveValidation()
    }
}

AfterHotReloadEffect

A composable effect that registers an action to be called after each successful hot reload.
@Composable
@DelicateHotReloadApi
public expect fun AfterHotReloadEffect(action: () -> Unit)
Requires @OptIn(DelicateHotReloadApi::class)This API should be used with caution and only in development contexts.
action
() -> Unit
required
A lambda function that will be called on the main thread after each successful hot reload. This callback is invoked after:
  • Code has been successfully reloaded
  • Objects have been migrated to new classes
  • Static fields have been re-initialized (if necessary)
The callback runs before the next frame is rendered.

Lifecycle

The effect follows standard Compose lifecycle:
  1. When the composable enters the composition, the hook is registered
  2. The hook remains active as long as the composable is in the composition
  3. When the composable leaves the composition, the hook is automatically cleaned up
Automatic CleanupUnlike staticHotReloadScope.invokeAfterHotReload(), AfterHotReloadEffect automatically unregisters the hook when the composable leaves the composition. You don’t need to manually manage cleanup.

Usage Examples

Basic Usage

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import org.jetbrains.compose.reload.AfterHotReloadEffect
import org.jetbrains.compose.reload.DelicateHotReloadApi

@OptIn(DelicateHotReloadApi::class)
@Composable
fun MyComponent() {
    var counter by remember { mutableStateOf(0) }
    
    AfterHotReloadEffect {
        println("Hot reload occurred! Counter is currently: $counter")
    }
    
    Button(onClick = { counter++ }) {
        Text("Count: $counter")
    }
}

Refreshing Data After Reload

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import org.jetbrains.compose.reload.AfterHotReloadEffect
import org.jetbrains.compose.reload.DelicateHotReloadApi

@OptIn(DelicateHotReloadApi::class)
@Composable
fun DataDisplay(repository: DataRepository) {
    var data by remember { mutableStateOf(repository.getData()) }
    
    AfterHotReloadEffect {
        // Refresh data after hot reload
        data = repository.getData()
    }
    
    Text("Data: $data")
}

Logging Reload Events

import androidx.compose.runtime.Composable
import org.jetbrains.compose.reload.AfterHotReloadEffect
import org.jetbrains.compose.reload.DelicateHotReloadApi
import java.time.LocalDateTime

@OptIn(DelicateHotReloadApi::class)
@Composable
fun App() {
    AfterHotReloadEffect {
        val timestamp = LocalDateTime.now()
        println("[Hot Reload] App reloaded at $timestamp")
    }
    
    // Your app content
    MainScreen()
}

Re-initializing Resources

import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import org.jetbrains.compose.reload.AfterHotReloadEffect
import org.jetbrains.compose.reload.DelicateHotReloadApi

@OptIn(DelicateHotReloadApi::class)
@Composable
fun MediaPlayer() {
    val player = remember { createMediaPlayer() }
    
    AfterHotReloadEffect {
        // Reinitialize player after code changes
        player.reset()
        player.prepare()
    }
    
    DisposableEffect(Unit) {
        onDispose {
            player.release()
        }
    }
    
    // Player UI
}

Platform Behavior

  • JVM with hot reload active: Registers a real hook that fires after each reload
  • All other platforms: No-op, the action is never called

Exception Handling

If the action lambda throws an exception:
  • The exception is wrapped in an InvokeAfterHotReloadException
  • It’s propagated through the coroutine context
  • Other reload hooks will still execute

DevelopmentEntryPoint

A legacy composable function that provides an entry point for hot reload.
@Composable
@DelicateHotReloadApi
@Deprecated("DevelopmentEntryPoint {} is no longer needed and the default dependency will be removed soon")
public expect fun DevelopmentEntryPoint(child: @Composable () -> Unit)
DeprecatedThis function is deprecated and no longer necessary. When using regular Compose Window components, there is no need to manually wrap code with DevelopmentEntryPoint.
child
@Composable () -> Unit
required
The composable content to render

Migration

If you’re currently using DevelopmentEntryPoint, you can safely remove it:

Before

import org.jetbrains.compose.reload.DelicateHotReloadApi
import org.jetbrains.compose.reload.DevelopmentEntryPoint

@OptIn(DelicateHotReloadApi::class)
fun main() = application {
    Window(onCloseRequest = ::exitApplication) {
        DevelopmentEntryPoint {
            App()
        }
    }
}

After

fun main() = application {
    Window(onCloseRequest = ::exitApplication) {
        App()
    }
}

When You Might Still Need It

The DevelopmentEntryPoint function might only be applicable for:
  • Non-window-based applications
  • Custom rendering contexts
  • Experimental platforms
For standard Compose Desktop and Compose Multiplatform applications using Window, this function is unnecessary.

Behavior

  • When hot reload is active: Forwards to internal hot reload infrastructure
  • When hot reload is not active: Simply renders the child content directly

HotReloadScope

Non-composable alternative for reload hooks

Runtime Overview

Overview of all runtime APIs

Build docs developers (and LLMs) love