Project setup
Repositories, Gradle properties, JDK toolchains and multi-module layout for a real-world Nucleus project.
The quickstart fits in one module. Real projects split UI, business logic and platform glue — and Nucleus's à la carte modules expect a layout where dependencies flow in one direction.
TL;DR
- Resolve the plugin from Gradle Plugin Portal; resolve runtime modules from Maven Central.
- Pin a JDK toolchain (17 minimum; 25 for AOT cache).
- A typical layout is
:app(Nucleus entry point) →:ui(Compose) →:domain(pure Kotlin), with platform integration code grouped where it's used.
Repositories
// settings.gradle.kts
pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
google()
}
}
dependencyResolutionManagement {
repositories {
mavenCentral()
google()
}
}google() is needed only if you pull Compose Multiplatform from there or share modules with Android.
Plugin and runtime versions
// build.gradle.kts (app module)
plugins {
kotlin("jvm") version "2.0.21"
id("org.jetbrains.compose") version "1.7.0"
id("dev.nucleusframework") version "2.0.0"
}All dev.nucleusframework:nucleus.* runtime artifacts publish the same version. Pin once:
val nucleusVersion = "2.0.0"
dependencies {
implementation(compose.desktop.currentOs)
implementation("dev.nucleusframework:nucleus.nucleus-application:$nucleusVersion")
implementation("dev.nucleusframework:nucleus.decorated-window-tao:$nucleusVersion")
// pull in only what you need
implementation("dev.nucleusframework:nucleus.notification-common:$nucleusVersion")
implementation("dev.nucleusframework:nucleus.global-hotkey:$nucleusVersion")
}nucleus-application is the umbrella; it transitively pulls core-runtime, aot-runtime and graalvm-runtime. Every other module is opt-in.
JDK toolchain
// gradle/libs.versions.toml or directly:
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(25))
// Optional: pin the vendor for reproducible builds
// vendor.set(JvmVendorSpec.JETBRAINS)
}
}Use JDK 17 if you don't need the AOT cache, JDK 25 to enable it (enableAotCache = true in nativeDistributions). For GraalVM native images, configure nucleus.application.graalvm { javaLanguageVersion.set(25) } — see Configuration.
Recommended gradle.properties
org.gradle.jvmargs=-Xmx4g -XX:+UseG1GC
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=true
kotlin.code.style=officialConfiguration cache works with Nucleus's plugin; if you hit a snag, file an issue.
Multi-module layout
A pragmatic split:
my-app/
├── settings.gradle.kts
├── build.gradle.kts ← shared conventions, no plugins
├── app/ ← Nucleus entry point + main()
│ └── build.gradle.kts ← applies dev.nucleusframework
├── ui/ ← Compose Composables, themes
│ └── build.gradle.kts
└── domain/ ← pure Kotlin: models, repositories, services
└── build.gradle.ktsRules:
- Only
:appappliesdev.nucleusframework. Only:appdeclaresnucleus.application { … }. :domainstays pure Kotlin and can be shared with Android/iOS later (move it under a KMPcommonMainsource set when that day comes).- Platform-specific glue (e.g. a macOS dock menu, a Windows jump list) goes next to the code that uses it — most often inside
:app.
Multiplatform sharing
Nucleus's runtime modules are JVM-only, but the :domain and :ui modules can be Kotlin Multiplatform without changing anything in :app. The JVM target of those modules is what :app actually consumes.
Hot Reload
Compose Hot Reload is supported out of the box — Nucleus extends the Compose plugin rather than replacing it. The mainClass you set in nucleus.application is propagated to compose.desktop.application.mainClass, so hotRun resolves the entry point with no extra config.
Next
- Configuration — the full Gradle DSL.
- Modules — how Nucleus modules compose.