Migration from org.jetbrains.compose¶
Potassium is a drop-in extension of the official JetBrains Compose Desktop plugin. All existing configuration is preserved — Potassium only adds new capabilities.
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("com.seanproctor.potassium") version "0.1.0"
}
The official
org.jetbrains.composeplugin remains — Potassium extends it, not replaces it.
The plugin is published to Maven Central, so make sure mavenCentral() is in your pluginManagement.repositories:
Step 2: Update Imports¶
Replace the JetBrains Compose DSL imports with the Potassium equivalents:
-import org.jetbrains.compose.desktop.application.dsl.TargetFormat
+import com.seanproctor.potassium.dsl.MacOSTargetFormat
+import com.seanproctor.potassium.dsl.WindowsTargetFormat
+import com.seanproctor.potassium.dsl.LinuxTargetFormat
This applies to all DSL types used in your build.gradle.kts (e.g. MacOSTargetFormat, CompressionLevel, SigningAlgorithm, etc.). Potassium splits the single Compose TargetFormat into per-OS enums declared inside each platform block — see Step 3.
Step 3: Use the Potassium DSL¶
Replace the compose.desktop.application block with potassium for packaging and distribution:
-compose.desktop.application {
+potassium {
mainClass = "com.example.MainKt"
- targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "MyApp"
packageVersion = "1.0.0"
macOS {
+ targetFormats(MacOSTargetFormat.Dmg)
bundleID = "com.example.myapp"
iconFile.set(project.file("icons/app.icns"))
}
windows {
+ targetFormats(WindowsTargetFormat.Msi)
iconFile.set(project.file("icons/app.ico"))
}
linux {
+ targetFormats(LinuxTargetFormat.Deb)
iconFile.set(project.file("icons/app.png"))
}
}
Using Compose Hot Reload?
Some Compose plugin tasks (like hotRun) read mainClass from the original compose.desktop.application block, not from potassium. If you use Compose Hot Reload, either keep a minimal Compose block alongside Potassium:
Or pass the property explicitly when running:
Step 4: Add Potassium Features (Optional)¶
Enable the features you need. All are opt-in:
potassium {
mainClass = "com.example.MainKt"
packageName = "MyApp"
packageVersion = "1.0.0"
// --- New Potassium features ---
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",
)
// Target formats — grouped per OS (with new Potassium targets)
macOS { targetFormats(MacOSTargetFormat.Dmg) }
windows { targetFormats(WindowsTargetFormat.Nsis) }
linux {
targetFormats(
LinuxTargetFormat.Deb,
LinuxTargetFormat.AppImage, LinuxTargetFormat.Snap, LinuxTargetFormat.Flatpak, // NEW
)
}
// Publishing
publish {
github {
enabled = true
owner = "myorg"
repo = "myapp"
}
}
// NSIS customization
windows {
nsis {
oneClick = false
allowToChangeInstallationDirectory = true
createDesktopShortcut = true
}
}
}
What Changes¶
| Feature | Before (compose) | After (potassium) |
|---|---|---|
| DSL entry point | compose.desktop.application |
potassium |
| DSL imports | org.jetbrains.compose.desktop.application.dsl.* |
com.seanproctor.potassium.dsl.* |
| Compose dependencies | compose.desktop.currentOs, compose("…") |
Unchanged — keep using the official org.jetbrains.compose DSL. Potassium no longer re-exposes a potassium.* Compose-dependency accessor. |
| Target formats | DMG, PKG, MSI, EXE, DEB, RPM | + NSIS, AppX, Portable, AppImage, Snap, Flatpak, archives |
| Native lib cleanup | Manual | cleanupNativeLibs = true |
| AOT cache | Not available | enableAotCache = true |
| Splash screen | Manual | splashImage = "splash.png" |
| Deep links | Manual (macOS only via Info.plist) | Cross-platform protocol("name", "scheme") |
| File associations | Limited | Cross-platform fileAssociation() |
| NSIS config | Not available | Full nsis { } DSL |
| AppX config | Not available | Full appx { } DSL |
| Snap config | Not available | Full snap { } DSL |
| Flatpak config | Not available | Full flatpak { } DSL |
| Store pipeline | Not available | Automatic dual pipeline for store formats (PKG, AppX, Flatpak) with sandboxing for PKG and Flatpak |
| Auto-update | Not available | Built-in with YML metadata |
| Code signing | macOS only | + Windows PFX / Azure Artifact Signing |
| DMG appearance | Not customizable (jpackage defaults) | Full dmg { } DSL: background, icon size, window layout, content positioning, format (details) |
| Artifact naming | Fixed | Template with artifactName |
Important Differences from Compose Desktop¶
homepage is Required for Linux DEB¶
Unlike Compose Desktop (which uses jpackage), Potassium uses electron-builder for packaging. Electron-builder requires the homepage property when building DEB packages. Without it, the build will fail with:
Make sure to set it in your potassium block:
This also applies to GraalVM native image packaging (packageGraalvmLinux).
What Stays the Same¶
Everything from the official plugin works unchanged:
mainClass,jvmArgs- Package metadata, icons, resources (now set directly in the
potassiumblock) buildTypes/ ProGuard configurationmodules()/includeAllModules- The standard Gradle tasks (
run,packageDistributionForCurrentOS, the per-platformpackageMacOS/packageWindows/packageLinux, etc.) compose.desktop.currentOsdependency- Source set configuration
- Compose Hot Reload — works as usual since Potassium extends the Compose plugin. Note:
hotRunreadsmainClassfromcompose.desktop.application, so set it there too or pass-PmainClass=...(see Step 3)