Nucleus
Migrate

Migrating from JetBrains Compose Desktop

Nucleus extends the official Compose Desktop plugin — keep what works, gain ten more formats, auto-update, GraalVM, store pipeline, native window decorations.

Nucleus is a drop-in extension of org.jetbrains.compose Desktop. All existing configuration is preserved — Nucleus only adds new capabilities. If you can build and ship today with the JetBrains plugin, you can switch in an afternoon.

TL;DR

  • Add id("dev.nucleusframework") next to the JetBrains plugin (don't remove it).
  • Move compose.desktop.application { … } to nucleus.application { … } and update DSL imports.
  • All your existing settings (mainClass, nativeDistributions, buildTypes, modules) work unchanged.
  • Set homepage on nativeDistributions — required by electron-builder for DEB.

Step 1 — Add the plugin

 plugins {
     id("org.jetbrains.kotlin.jvm") version "2.3.10"
     id("org.jetbrains.kotlin.plugin.compose") version "2.3.10"
     id("org.jetbrains.compose") version "1.10.1"
+    id("dev.nucleusframework") version "2.0.0"
 }

The official org.jetbrains.compose plugin remains — Nucleus extends it, not replaces it.

Step 2 — Update imports

Replace the JetBrains Compose DSL imports with the Nucleus equivalents:

-import org.jetbrains.compose.desktop.application.dsl.TargetFormat
+import dev.nucleusframework.desktop.application.dsl.TargetFormat

Same for CompressionLevel, SigningAlgorithm, etc.

Step 3 — Use the Nucleus DSL

Move the application block:

-compose.desktop.application {
+nucleus.application {
     mainClass = "com.example.MainKt"

     nativeDistributions {
         targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
         packageName = "MyApp"
         packageVersion = "1.0.0"

         macOS {
             bundleID = "com.example.myapp"
             iconFile.set(project.file("icons/app.icns"))
         }

         windows {
             iconFile.set(project.file("icons/app.ico"))
         }

         linux {
             iconFile.set(project.file("icons/app.png"))
         }
     }
 }

Compose Hot Reload

Nucleus auto-propagates nucleus.application.mainClass to compose.desktop.application.mainClass, so Compose Hot Reload tasks (hotRun, hotSnapshotMain) resolve the entry point with no extra config. On macOS with decorated-window-tao, -XstartOnFirstThread is injected into Hot Reload's JavaExec tasks automatically.

Step 4 — Add Nucleus features (optional)

Everything below is opt-in. Add as needed:

nucleus.application {
    mainClass = "com.example.MainKt"

    nativeDistributions {
        targetFormats(
            TargetFormat.Dmg, TargetFormat.Nsis, TargetFormat.Deb,
            TargetFormat.AppImage, TargetFormat.Snap, TargetFormat.Flatpak, // new
        )
        packageName = "MyApp"
        packageVersion = "1.0.0"
        homepage = "https://myapp.example.com" // required for DEB

        cleanupNativeLibs = true
        enableAotCache = true
        splashImage = "splash.png"
        compressionLevel = CompressionLevel.Maximum
        artifactName = "\${name}-\${version}-\${os}-\${arch}.\${ext}"

        // Deep links
        protocol("MyApp", "myapp")

        // File associations
        fileAssociation(
            mimeType = "application/x-myapp",
            extension = "myapp",
            description = "MyApp Document",
        )

        // Publishing
        publish {
            github { enabled = true; owner = "myorg"; repo = "myapp" }
        }

        // NSIS customization
        windows {
            nsis {
                oneClick = false
                allowToChangeInstallationDirectory = true
                createDesktopShortcut = true
            }
        }
    }
}

Step 5 — Add runtime libraries (optional)

dependencies {
    implementation(compose.desktop.currentOs)

    implementation("dev.nucleusframework:nucleus.core-runtime:2.0.0")
    implementation("dev.nucleusframework:nucleus.aot-runtime:2.0.0")           // if enableAotCache
    implementation("dev.nucleusframework:nucleus.updater-runtime:2.0.0")        // if publishing
    implementation("dev.nucleusframework:nucleus.taskbar-progress:2.0.0")
    implementation("dev.nucleusframework:nucleus.nucleus-application:2.0.0")    // for nucleusApplication { }
}

If you want the unified nucleusApplication { } entry point with automatic single-instance, deep links, and AOT wiring, see the Nucleus 1.x → 2.0 guide — the same application { } → nucleusApplication { } swap applies whether you're coming from 1.x or vanilla CMP.

What changes

FeatureBefore (compose)After (nucleus)
DSL entry pointcompose.desktop.applicationnucleus.application
DSL importsorg.jetbrains.compose.desktop.application.dsl.*dev.nucleusframework.desktop.application.dsl.*
Target formatsDMG, PKG, MSI, EXE, DEB, RPM+ NSIS, AppX, Portable, AppImage, Snap, Flatpak, archives
Native lib cleanupManualcleanupNativeLibs = true
AOT cacheNot availableenableAotCache = true
Splash screenManualsplashImage = "splash.png"
Deep linksManual, per-OSprotocol("name", "scheme")
File associationsLimitedCross-platform fileAssociation()
NSIS configNot availableFull nsis { } DSL
AppX configNot availableFull appx { } DSL
Snap configNot availableFull snap { } DSL
Flatpak configNot availableFull flatpak { } DSL
Store pipelineNot availableAutomatic sandboxed pipeline for PKG, AppX, Flatpak
Auto-updateNot availableBuilt-in with YAML metadata
Code signingmacOS only+ Windows PFX / Azure Artifact Signing
DMG appearanceNot customizableFull dmg { } DSL (details)
Artifact namingFixedTemplate with artifactName

Important: homepage is required for DEB

Unlike Compose Desktop (which uses jpackage), Nucleus uses electron-builder for packaging — electron-builder requires homepage for DEB. Without it the build fails with:

Please specify project homepage, see https://electron.build/configuration
nativeDistributions {
    homepage = "https://myapp.example.com"
}

Also applies to GraalVM Native Image DEB packaging (packageGraalvmDeb).

What stays the same

  • mainClass, jvmArgs.
  • nativeDistributions block (metadata, icons, resources).
  • buildTypes / ProGuard.
  • modules() / includeAllModules.
  • All existing Gradle tasks (run, packageDmg, packageDeb, …).
  • compose.desktop.currentOs dependency.
  • Source set configuration.
  • Compose Hot Reload — works out of the box.

Next steps

  • Want native window decorations and the Tao backend? See windowing and Tao.
  • Want auto-update? See auto-update.
  • Want GraalVM Native Image? See GraalVM.
  • Migrating an entire 1.x codebase? See from 1.x — same plugin swap plus a nucleusApplication upgrade.