compose-native-host
0.0.3indexedEmbed Compose UI into native windowing hosts, GPU Metal renderer for smooth resizing/scrolling, GraalVM native-image support, multi-window/multi-runtime, Gradle plugin automates native build.
Embed Compose UI into native windowing hosts, GPU Metal renderer for smooth resizing/scrolling, GraalVM native-image support, multi-window/multi-runtime, Gradle plugin automates native build.
Compose in native macOS and Windows windows

[!IMPORTANT] This project is experimental. API and features are subject to change.
Gradle
// build.gradle.kts
plugins {
id("io.github.letmutex.compose.nativehost") version "<VERSION>"
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.compose.multiplatform)
}
kotlin {
jvm("desktop")
sourceSets {
val desktopMain by getting {
dependencies {
implementation("io.github.letmutex.compose-native-host:runtime:<VERSION>")
implementation(compose.desktop.currentOs)
}
}
}
}
composeNativeHost {
appName.()
bundleIdentifier.()
}
compose.desktop {
application {
mainClass =
}
}
Kotlin
// src/desktopMain/kotlin/example/Main.kt
package example
import letmutex.compose.nativehost.ComposeNativeHost
fun main() = ComposeNativeHost {
App()
}
Swift
Use a GraalVM JDK that already has native-image available under bin/.
Environment
-PgraalvmHome=/path/to/graalvm, GRAALVM_HOME=/path/to/graalvm, org.gradle.java.home=/path/to/graalvm, or JAVA_HOME=/path/to/graalvm.Gradle
composeNativeHost {
appName.set("Sample")
bundleIdentifier.set("example.sample")
nativeImage {
mainClasses("example.MainKt")
}
}
Swift startups
final class SampleAppDelegate: ComposeAppDelegateBase {
override init() {
super.init(configuration: ComposeHostConfiguration(startups: [.jvm, .sharedLibrary()]))
}
}
Use .jvm so the same host still runs without a bundled shared library, and add .sharedLibrary() so the staged native image bundle can bind the generated Graal runtime when present.
Use macosRun or windowsRun for the staged JVM application. On macOS and Windows, you can also use macosNativeImageRun or windowsNativeImageRun for the staged native image bundle.
# macOS JVM run
./gradlew -p samples :appkit:macosRun
# Windows JVM run
./gradlew -p samples :mixed:windowsRun
# macOS native image run
./gradlew -p samples :appkit:macosNativeImageRun
# Windows native image run
./gradlew -p samples :mixed:windowsNativeImageRun
# build JVM .app / Windows staged bundle
./gradlew -p samples :appkit:macosCreateDistributable
./gradlew -p samples :mixed:windowsCreateDistributable
# build Native Image .app / Windows Native Image staged bundle
./gradlew -p samples :appkit:macosNativeImageCreateDistributable
./gradlew -p samples :mixed:windowsNativeImageCreateDistributable
# package JVM .dmg / Windows MSI
./gradlew -p samples :appkit:macosPackageDmg
./gradlew -p samples :mixed:windowsPackageMsi
# package Native Image .dmg / Windows Native Image MSI
./gradlew -p samples :appkit:macosNativeImagePackageDmg
./gradlew -p samples :mixed:windowsNativeImagePackageMsi
# package JVM release .dmg / Windows release MSI
./gradlew -p samples :appkit:macosPackageReleaseDmg
./gradlew -p samples :mixed:windowsPackageReleaseMsi
# package Native Image release .dmg / Windows Native Image release MSI
./gradlew -p samples :appkit:macosNativeImagePackageReleaseDmg
./gradlew -p samples :mixed:windowsNativeImagePackageReleaseMsi
runtime: shared host API plus macOS runtime, native bridge, and native host sources.Debugging environment variables:
COMPOSE_NATIVE_HOST_FRAME_TIMINGS=1: Enable logging of frame timings (dispatch delay, input drain, scene render, etc.) to stdout for performance analysis.COMPOSE_NATIVE_HOST_VSYNC_DELAY=1: Enable analysis of VSync signal delivery delay from the display link to the Kotlin runtime.You own the native App entry point in Swift (macOS) or C++ (Windows). Your app's native sources (e.g., in src/macosMain/swift or src/windowsMain/cpp) define the lifecycle, window creation, and message/event loop.
A thin bridge layer (Objective C on macOS, C++ on Windows) handles low-level JNI communication between the native host and the Kotlin JVM or GraalVM runtime.
Rendering is performed directly on the GPU via Metal (macOS) or Direct3D 12 (Windows). The custom renderer bypasses AWT/Swing, ensuring smooth synchronization with window resizing and animations.
The Gradle plugin automates the complex native build pipeline. It:
swiftc (macOS) or MSVC cl.exe (Windows)..dylib / .dll) and launcher into the app bundle/folder.+-------------------+ +--------------+ +----------------+ +-------------+
| Native App Host | --(1)--> | Bridge Layer | --(2)--> | Kotlin Runtime | --(3)--> | GPU Texture |
| (Swift / C++ Win) | | (JNI / C-API)| | (JVM / Native) | | (Metal/D3D) |
+-------------------+ +--------------+ +----------------+ +-------------+
Copyright 2026 letmutex
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
// src/macosMain/swift/SwiftUiApp.swift
import SwiftUI
import ComposeNativeHost
final class SampleAppDelegate: ComposeAppDelegateBase {
fileprivate lazy var runtime = makeComposeRuntime(
configuration: ComposeRuntimeConfiguration(kotlinMainClass: "example.MainKt")
)
}
@main
struct SampleApp: App {
(SampleAppDelegate.self) private var appDelegate
var body: some Scene {
WindowGroup {
ComposeView(runtime: appDelegate.runtime)
}
}
}
macosNativeImageRun, windowsNativeImageRun and the native image bundle tasks use that GraalVM home directly.macosRun and windowsRun still use a regular JVM launch path.gradle-plugin: Gradle plugin for macOS launcher generation, bundle staging, and macOS app tasks.samples/compose: pure Compose Desktop sample app and shared Kotlin sample content.samples/appkit: AppKit-owned sample window using the shared hosted Kotlin sample.samples/swiftui: SwiftUI-owned sample window using the shared hosted Kotlin sample.samples/swiftui-min: minimal SwiftUI-owned sample extracted from the setup shown above.samples/mixed: AppKit-owned window with SwiftUI content composition around the hosted Compose surface.Surfaced from shared tags and platforms — no rankings paid for.