# Potassium Packager > Potassium is a Gradle plugin for packaging and distributing Compose / JVM desktop applications on macOS, Windows, and Linux. It extends the official JetBrains Compose Desktop plugin and adds many installer formats (deb/rpm/AppImage/snap/flatpak, msi/exe/appx, dmg/pkg), code signing & notarization, electron-builder-based auto-update, and GraalVM Native Image builds. Plugin id: com.seanproctor.potassium. - Docs: https://github.com/sproctor/potassium-packager - GitHub: https://github.com/sproctor/potassium-packager - Maven Central: https://central.sonatype.com/artifact/com.seanproctor/potassium-packager - License: MIT **Potassium is a Gradle plugin for packaging and distributing Compose / JVM desktop applications** on macOS, Windows, and Linux. It is a drop-in extension of the official JetBrains Compose Desktop plugin — keep your existing `compose.desktop` configuration and opt into the capabilities you need. Potassium picks up where jpackage stops: more installer formats, real code signing and notarization, built-in auto-update, and GraalVM Native Image builds, all from a single Gradle DSL. ## What it does ### Ship everywhere - **Many installer formats** — Linux `deb` / `rpm` / `AppImage` / `snap` / `flatpak`, Windows `msi` / `exe` (NSIS) / `appx` / portable, macOS `dmg` / `pkg`, plus archives (`zip`, `tar`, `7z`) - **Store-ready** — Mac App Store, Microsoft Store, Snapcraft, Flathub - **Code signing & notarization** — Windows (PFX / Azure) and macOS, built into the build pipeline - **Auto-update** — electron-builder-compatible update metadata (`latest-*.yml`) generated alongside your installers, with SHA-512 verification - **Deep links & file associations** — protocol handlers and file type registration on all platforms ### Go further - **GraalVM Native Image** — compile your app into a standalone native binary. Potassium resolves the reachability metadata transparently, so most apps build with zero manual reflection config. - **AOT cache** — enable the JDK 25+ ahead-of-time cache for faster startup with a single flag. - **ProGuard release builds** — optimization and obfuscation for production. - **Trusted CA certificates** — import custom root CAs into the bundled JVM's `cacerts` at build time. - **CI/CD ready** — reusable GitHub Actions for multi-platform matrix builds, universal macOS binaries, and MSIX bundles. ## Quick start ```kotlin // settings.gradle.kts pluginManagement { repositories { gradlePluginPortal() mavenCentral() } } ``` ```kotlin // build.gradle.kts plugins { kotlin("jvm") version "..." id("org.jetbrains.kotlin.plugin.compose") version "..." id("org.jetbrains.compose") version "..." id("com.seanproctor.potassium") version "0.1.0" } potassium { mainClass = "com.example.MainKt" packageName = "MyApp" packageVersion = "1.0.0" macOS { targetFormats(MacOSTargetFormat.Dmg) } windows { targetFormats(WindowsTargetFormat.Nsis) } linux { targetFormats(LinuxTargetFormat.Deb) } } ``` ```bash ./gradlew run # Run locally ./gradlew packageDistributionForCurrentOS # Build installers for the current OS ``` **Kotlin DSL imports:** The Kotlin DSL types live under `com.seanproctor.potassium.*` (for example `import com.seanproctor.potassium.dsl.MacOSTargetFormat`). ## Coordinates - **Plugin id:** `com.seanproctor.potassium` - **Latest version:** `0.1.0` - **Published to:** Maven Central - **Repository:** [github.com/sproctor/potassium-packager](https://github.com/sproctor/potassium-packager) ## Requirements | Requirement | Version | Note | |-------------|---------|------| | JDK | 17+ (25+ for AOT cache) | | | Gradle | 8.0+ | | | Kotlin | 2.0+ | | | Node.js | 18+ | Required by electron-builder for installer formats | ## Next steps - [Getting Started](getting-started.md) — install the plugin and build your first installer - [Configuration](configuration.md) — full DSL reference - [Migration from org.jetbrains.compose](migration.md) — switch an existing Compose Desktop project ## License MIT — See [LICENSE](https://github.com/sproctor/potassium-packager/blob/main/LICENSE). --- # Getting Started ## Prerequisites Potassium uses [electron-builder](https://www.electron.build/) under the hood to produce platform-specific installers (DMG, NSIS, DEB, RPM, AppImage, etc.). This requires **Node.js 18+** and **npm** installed on your build machine. ```bash # Verify your installation node --version # v18.0.0 or later npm --version ``` **CI/CD:** The `setup-potassium` composite action installs Node.js automatically. See [CI/CD](ci-cd.md) for details. ## Installation The plugin is published to Maven Central. Add Maven Central to your plugin repositories, then apply the plugin in your build script: ```kotlin // settings.gradle.kts pluginManagement { repositories { gradlePluginPortal() mavenCentral() } } ``` ```kotlin // build.gradle.kts plugins { kotlin("jvm") version "..." id("org.jetbrains.kotlin.plugin.compose") version "..." id("org.jetbrains.compose") version "..." id("com.seanproctor.potassium") version "0.1.0" } ``` **Kotlin DSL imports:** The Kotlin DSL types live under `com.seanproctor.potassium.*` (for example `import com.seanproctor.potassium.dsl.MacOSTargetFormat`). ## Minimal Configuration ```kotlin potassium { mainClass = "com.example.MainKt" packageName = "MyApp" packageVersion = "1.0.0" macOS { targetFormats(MacOSTargetFormat.Dmg) } windows { targetFormats(WindowsTargetFormat.Nsis) } linux { targetFormats(LinuxTargetFormat.Deb) } } ``` ## Gradle Tasks ### Development | Task | Description | |------|-------------| | `run` | Run the application from the IDE/terminal | | `runDistributable` | Run the packaged application image | #### Compose Hot Reload Potassium is fully compatible with [Compose Hot Reload](https://kotlinlang.org/docs/multiplatform/compose-hot-reload.html). Since Potassium extends the Compose plugin (not replaces it), Hot Reload works out of the box. The `hotRun` task reads `mainClass` from the `compose.desktop.application` block. If you only set it in `potassium`, add a minimal Compose block: ```kotlin compose.desktop.application { mainClass = "com.example.MainKt" } ``` Or pass it via the command line: ```bash ./gradlew hotRun -PmainClass=com.example.MainKt ``` ### Packaging | Task | Description | |------|-------------| | `packageDistributionForCurrentOS` | Build all configured formats for the current OS | | `package` | Build all the current OS's non-store formats in one invocation (`packageMacOS` / `packageWindows` / `packageLinux`) | | `packagePkg` / `packageAppX` / `packageFlatpak` | Build a store format (each built separately) | | `packageReleaseDistributionForCurrentOS` | Same as above with ProGuard release build | | `createDistributable` | Create the application image without an installer | | `createReleaseDistributable` | Same with ProGuard | ### Utility | Task | Description | |------|-------------| | `suggestModules` | Suggest JDK modules required by your dependencies | | `packageUberJarForCurrentOS` | Create a single fat JAR with all dependencies | ### Running a Specific Task ```bash # Build all configured macOS formats (e.g. DMG + ZIP) in one invocation ./gradlew packageMacOS # Build all configured Windows formats (e.g. NSIS + MSI) in one invocation ./gradlew packageWindows # Build all configured Linux formats (e.g. DEB + RPM + AppImage) in one invocation ./gradlew packageLinux # Build all formats for current OS (incl. store formats) ./gradlew packageDistributionForCurrentOS # Release build (with ProGuard) ./gradlew packageReleaseDistributionForCurrentOS ``` ## Output Location Build artifacts are generated in: ``` build/potassium/binaries/main// build/potassium/binaries/main-release// # Release builds ``` Override with: ```kotlin potassium { outputBaseDir.set(project.layout.buildDirectory.dir("custom-output")) } ``` ## JDK Modules The plugin does not automatically detect required JDK modules. Use `suggestModules` to identify them: ```bash ./gradlew suggestModules ``` Then declare them in the DSL: ```kotlin potassium { modules("java.sql", "java.net.http", "jdk.accessibility") } ``` Or include everything (larger binary): ```kotlin potassium { includeAllModules = true } ``` ## Application Icons Provide platform-specific icon files: ```kotlin potassium { macOS { iconFile.set(project.file("icons/app.icns")) } windows { iconFile.set(project.file("icons/app.ico")) } linux { iconFile.set(project.file("icons/app.png")) } } ``` | Platform | Format | Recommended Size | |----------|--------|------------------| | macOS | `.icns` | 1024x1024 | | Windows | `.ico` | 256x256 | | Linux | `.png` | 512x512 | ## Application Resources Include extra files in the installation directory via `appResourcesRootDir`: ```kotlin potassium { appResourcesRootDir.set(project.layout.projectDirectory.dir("resources")) } ``` Resource directory structure: ``` resources/ common/ # Included on all platforms macos/ # macOS only macos-arm64/ # macOS Apple Silicon only macos-x64/ # macOS Intel only windows/ # Windows only linux/ # Linux only ``` Access at runtime: ```kotlin val resourcesDir = File(System.getProperty("compose.application.resources.dir")) ``` ## Next Steps - [Configuration](configuration.md) — Full DSL reference - [macOS](targets/macos.md) / [Windows](targets/windows.md) / [Linux](targets/linux.md) — Platform-specific options - [CI/CD](ci-cd.md) — Automate builds with GitHub Actions --- # Configuration All Potassium configuration lives inside the `potassium { }` block in your `build.gradle.kts`. ## Overview ```kotlin potassium { mainClass = "com.example.MainKt" jvmArgs += listOf("-Xmx512m") buildTypes { release { proguard { isEnabled = true optimize = true obfuscate.set(false) configurationFiles.from(project.file("proguard-rules.pro")) } } } // Package metadata appName = "My App" // Display name (installer, .desktop, Start Menu) packageName = "MyApp" // Technical name (executable, package file) packageVersion = "1.0.0" description = "My awesome desktop app" vendor = "My Company" copyright = "Copyright 2025 My Company" homepage = "https://myapp.example.com" licenseFile.set(project.file("LICENSE")) // JDK modules modules("java.sql", "java.net.http") // Potassium features cleanupNativeLibs = true enableAotCache = true splashImage = "splash.png" compressionLevel = CompressionLevel.Maximum artifactName = "${name}-${version}-${os}-${arch}.${ext}" // Deep links & file associations protocol("MyApp", "myapp") fileAssociation( mimeType = "application/x-myapp", extension = "myapp", description = "MyApp Document", ) // Publishing publish { /* ... */ } // Platform-specific — target formats are grouped per OS here macOS { targetFormats(MacOSTargetFormat.Dmg) /* ... */ } windows { targetFormats(WindowsTargetFormat.Nsis) /* ... */ } linux { targetFormats(LinuxTargetFormat.Deb) /* ... */ } } ``` ## Target Formats Formats are grouped per OS and declared inside the matching platform block. All of a platform's non-store formats build in a **single** electron-builder invocation (`packageMacOS` / `packageWindows` / `packageLinux`); store formats (PKG, AppX, Flatpak) build separately. ```kotlin macOS { targetFormats(MacOSTargetFormat.Dmg, MacOSTargetFormat.Pkg) } windows { targetFormats(WindowsTargetFormat.Nsis, WindowsTargetFormat.Msi) } linux { targetFormats(LinuxTargetFormat.Deb, LinuxTargetFormat.Rpm, LinuxTargetFormat.AppImage) } ``` | OS | Format | Built by | Notes | |----|--------|----------|-------| | macOS | `MacOSTargetFormat.Dmg` | `packageMacOS` | | | macOS | `MacOSTargetFormat.Pkg` | `packagePkg` | App Store — built separately | | Windows | `WindowsTargetFormat.Nsis` | `packageWindows` | NSIS installer (`.exe`) | | Windows | `WindowsTargetFormat.Exe` | `packageWindows` | Alias for `Nsis` — same output | | Windows | `WindowsTargetFormat.NsisWeb` | `packageWindows` | NSIS web installer | | Windows | `WindowsTargetFormat.Msi` | `packageWindows` | | | Windows | `WindowsTargetFormat.Portable` | `packageWindows` | | | Windows | `WindowsTargetFormat.AppX` | `packageAppX` | MSIX — built separately | | Linux | `LinuxTargetFormat.Deb` | `packageLinux` | | | Linux | `LinuxTargetFormat.Rpm` | `packageLinux` | | | Linux | `LinuxTargetFormat.AppImage` | `packageLinux` | | | Linux | `LinuxTargetFormat.Snap` | `packageLinux` | | | Linux | `LinuxTargetFormat.Flatpak` | `packageFlatpak` | Built separately | | all | `Zip` / `Tar` / `SevenZ` | `package` | Present in each OS enum (e.g. `MacOSTargetFormat.Zip`) | **One invocation per platform:** Configuring several formats for an OS (e.g. `Deb`, `Rpm`, `AppImage`) makes `packageLinux` build them all in one electron-builder run, rather than one run per format. Target all of an OS's formats at once: ```kotlin linux { targetFormats(*LinuxTargetFormat.entries.toTypedArray()) } ``` ## Package Metadata | Property | Type | Default | Description | |----------|------|---------|-------------| | `appName` | `String?` | `null` | Human-readable display name (installer title, `.desktop` Name, Start Menu). Falls back to `packageName` if not set. | | `packageName` | `String` | Gradle project name | Technical package/executable name. On Linux this should be lowercase (e.g. `zayit`). | | `packageVersion` | `String` | Gradle project version | Application version | | `description` | `String?` | `null` | Short application description | | `vendor` | `String?` | `null` | Publisher / company name | | `copyright` | `String?` | `null` | Copyright notice | | `homepage` | `String?` | `null` | Application homepage URL. **Required** for Linux DEB packaging (electron-builder enforces this). | | `licenseFile` | `RegularFileProperty` | — | Path to the license file | | `appResourcesRootDir` | `DirectoryProperty` | — | Root directory for bundled resources | | `outputBaseDir` | `DirectoryProperty` | `build/potassium/binaries` | Output directory for built packages | ### Version Set a single `packageVersion` (SemVer — it may include a pre-release suffix such as `1.2.3-beta.1`). There are no per-OS or per-format version overrides: each platform has different version rules, so Potassium and electron-builder format the one version per target automatically. | Target | Handling | `1.2.3-beta.1` → | |--------|----------|------------------| | Windows (NSIS/MSI) | pre-release suffix stripped to numeric `MAJOR.MINOR.PATCH` | `1.2.3` | | macOS (DMG/PKG) | pre-release suffix stripped for the app version | `1.2.3` | | Linux (DEB/RPM) | `-` replaced with `~` (sorts before the final release) | `1.2.3~beta.1` | | AppImage | full version preserved | `1.2.3-beta.1` | The pre-release identifier (`beta`, `alpha`, …) also selects the auto-update channel — see [Auto-Update](auto-update.md). ## Potassium-Specific Features ### Native Library Cleanup Strips `.dll`, `.so`, `.dylib` files for non-target platforms from dependency JARs, reducing package size significantly. ```kotlin potassium { cleanupNativeLibs = true } ``` ### AOT Cache (JDK 25+) Generates an ahead-of-time compilation cache for faster startup: ```kotlin potassium { enableAotCache = true } ``` Requires JDK 25+ and that the application self-terminates during the training run. ### Splash Screen Displays a splash screen during application startup: ```kotlin potassium { splashImage = "splash.png" // Relative to appResources } ``` ### Artifact Naming Customize output filenames with template variables: ```kotlin potassium { artifactName = "${name}-${version}-${os}-${arch}.${ext}" } ``` | Variable | Description | Example | |----------|-------------|---------| | `${name}` | Package name | `MyApp` | | `${version}` | Package version | `1.0.0` | | `${os}` | Operating system | `macos`, `windows`, `linux` | | `${arch}` | Architecture | `amd64`, `arm64` | | `${ext}` | File extension | `dmg`, `exe`, `deb` | ### Compression Level Controls compression for electron-builder formats: ```kotlin potassium { compressionLevel = CompressionLevel.Maximum } ``` | Level | Description | |-------|-------------| | `CompressionLevel.Store` | No compression | | `CompressionLevel.Normal` | Balanced (default) | | `CompressionLevel.Maximum` | Best compression (recommended for most formats) | **AppImage and Maximum Compression:** Using `CompressionLevel.Maximum` with AppImage causes extremely slow startup times (60s+) due to squashfs/FUSE decompression overhead. For AppImage targets, use `Normal` or `Store` instead. Other formats (DMG, NSIS, DEB, RPM, etc.) are not affected. See [electron-builder#7483](https://github.com/electron-userland/electron-builder/issues/7483) for details. ### Trusted CA Certificates Import custom CA certificates into the bundled JVM's `cacerts` keystore at build time. Useful for corporate proxies, VPN gateways, or filtering services that use a private root CA. ```kotlin potassium { trustedCertificates.from(files( "certs/company-proxy-ca.pem", )) } ``` Both PEM and DER formats are accepted. See [Trusted CA Certificates](trusted-certificates.md) for full details. ### Deep Links (Protocol Handler) Register a custom URL protocol across all platforms: ```kotlin potassium { protocol("MyApp", "myapp") // Registers myapp:// protocol } ``` - **macOS**: `CFBundleURLTypes` in `Info.plist` - **Windows**: Registry entries via NSIS/MSI - **Linux**: `MimeType` in `.desktop` file This registers the protocol at the OS level; handling the incoming deep link at runtime is up to your application. ### File Associations Register file type associations: ```kotlin potassium { fileAssociation( mimeType = "application/x-myapp", extension = "myapp", description = "MyApp Document", ) } ``` The cross-platform `fileAssociation()` method also accepts per-platform icon files: ```kotlin fileAssociation( mimeType = "application/x-myapp", extension = "myapp", description = "MyApp Document", linuxIconFile = project.file("icons/file.png"), windowsIconFile = project.file("icons/file.ico"), macOSIconFile = project.file("icons/file.icns"), ) ``` Multiple associations are supported by calling `fileAssociation()` multiple times. ## ProGuard (Release Builds) ```kotlin buildTypes { release { proguard { version = "7.8.1" isEnabled = true optimize = true obfuscate.set(false) // Disabled by default joinOutputJars.set(true) configurationFiles.from(project.file("proguard-rules.pro")) } } } ``` Release build tasks are suffixed with `Release`: ```bash ./gradlew packageReleaseMacOS # or packageReleaseWindows / packageReleaseLinux ./gradlew packageReleaseDistributionForCurrentOS ``` ## Full DSL Tree ``` potassium { mainClass jvmArgs buildTypes { release { proguard { isEnabled, version, optimize, obfuscate, joinOutputJars, configurationFiles } } } appName, packageName, packageVersion, description, vendor, copyright, homepage licenseFile, appResourcesRootDir, outputBaseDir modules(...), includeAllModules cleanupNativeLibs, enableAotCache, splashImage compressionLevel, artifactName protocol(name, vararg schemes) fileAssociation(mimeType, extension, description, linuxIconFile?, windowsIconFile?, macOSIconFile?) publish { github , s3 , generic } macOS { targetFormats(...), iconFile, bundleID, dockName, appCategory, layeredIconDir, signing , notarization , dmg , infoPlist } windows { targetFormats(...), iconFile, upgradeUuid, signing , nsis , appx } linux { targetFormats(...), iconFile, debMaintainer, debDepends, rpmRequires, appImage , snap , flatpak } } ``` ## Next Steps - Platform-specific configuration: [macOS](targets/macos.md) · [Windows](targets/windows.md) · [Linux](targets/linux.md) - [Code Signing](code-signing.md) — Sign and notarize your app - [Publishing](publishing.md) — Distribute via GitHub Releases, S3, or generic HTTP server --- # 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 ```diff 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.compose` plugin remains — Potassium extends it, not replaces it. The plugin is published to Maven Central, so make sure `mavenCentral()` is in your `pluginManagement.repositories`: ```kotlin // settings.gradle.kts pluginManagement { repositories { gradlePluginPortal() mavenCentral() } } ``` ## Step 2: Update Imports Replace the JetBrains Compose DSL imports with the Potassium equivalents: ```diff -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). ## Step 3: Use the Potassium DSL Replace the `compose.desktop.application` block with `potassium` for packaging and distribution: ```diff -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](https://kotlinlang.org/docs/multiplatform/compose-hot-reload.html), either keep a minimal Compose block alongside Potassium: ```kotlin compose.desktop.application { mainClass = "com.example.MainKt" } ``` Or pass the property explicitly when running: ```bash ./gradlew hotRun -PmainClass=com.example.MainKt ``` ## Step 4: Add Potassium Features (Optional) Enable the features you need. All are opt-in: ```kotlin 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](targets/macos.md#dmg-customization)) | | 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: ``` Please specify project homepage, see https://electron.build/configuration ``` Make sure to set it in your `potassium` block: ```kotlin potassium { homepage = "https://myapp.example.com" } ``` 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 `potassium` block) - `buildTypes` / ProGuard configuration - `modules()` / `includeAllModules` - The standard Gradle tasks (`run`, `packageDistributionForCurrentOS`, the per-platform `packageMacOS` / `packageWindows` / `packageLinux`, etc.) - `compose.desktop.currentOs` dependency - Source set configuration - [Compose Hot Reload](https://kotlinlang.org/docs/multiplatform/compose-hot-reload.html) — works as usual since Potassium extends the Compose plugin. Note: `hotRun` reads `mainClass` from `compose.desktop.application`, so set it there too or pass `-PmainClass=...` (see [Step 3](#step-3-use-the-potassium-dsl)) --- ## Documentation - [Getting Started](https://github.com/sproctor/potassium-packager/getting-started/) - [Configuration](https://github.com/sproctor/potassium-packager/configuration/) - [macOS Targets](https://github.com/sproctor/potassium-packager/targets/macos/) - [Windows Targets](https://github.com/sproctor/potassium-packager/targets/windows/) - [Linux Targets](https://github.com/sproctor/potassium-packager/targets/linux/) - [Sandboxing](https://github.com/sproctor/potassium-packager/sandboxing/) - [Code Signing](https://github.com/sproctor/potassium-packager/code-signing/) - [Auto Update](https://github.com/sproctor/potassium-packager/auto-update/) - [Publishing](https://github.com/sproctor/potassium-packager/publishing/) - [Trusted CA Certificates](https://github.com/sproctor/potassium-packager/trusted-certificates/) - [GraalVM Native Image](https://github.com/sproctor/potassium-packager/graalvm/index/) - [Configuration](https://github.com/sproctor/potassium-packager/graalvm/configuration/) - [Automatic Metadata Resolution](https://github.com/sproctor/potassium-packager/graalvm/automatic-metadata/) - [Runtime Bootstrap](https://github.com/sproctor/potassium-packager/graalvm/runtime-bootstrap/) - [Tasks & CI/CD](https://github.com/sproctor/potassium-packager/graalvm/tasks-ci/) - [Nucleus Native Access](https://github.com/sproctor/potassium-packager/native-access/index/) - [Supported Types](https://github.com/sproctor/potassium-packager/native-access/types/) - [Usage & Patterns](https://github.com/sproctor/potassium-packager/native-access/usage/) - [CI/CD](https://github.com/sproctor/potassium-packager/ci-cd/) - [Packaging](https://github.com/sproctor/potassium-packager/comparison/packaging/) - [Migration from org.jetbrains.compose](https://github.com/sproctor/potassium-packager/migration/) - [Roadmap](https://github.com/sproctor/potassium-packager/roadmap/) ## Full LLM Documentation - [llms-full.txt](https://github.com/sproctor/potassium-packager/llms-full.txt): Complete documentation in a single file