Why Nucleus
One language, one process, native everywhere — and how that compares to Electron, Tauri, and vanilla CMP.
Everywhere else, Kotlin owns the whole platform. On Android it's first-class. On iOS, Kotlin/Native reaches every UIKit and Foundation API. On the web, Kotlin/JS and Wasm draw Compose UIs with the full browser surface. Desktop was the holdout — you could render a window, but reaching the OS meant juggling pointers, compiling native libraries per platform, wiring JNI or FFM bridges, and learning a different native API for every OS. Nucleus closes the gap.
TL;DR
- One language for UI, business logic, OS calls, packaging.
- One process — no IPC bridge between renderer and main.
- Same Kotlin code that already runs on Android, iOS, web.
- Two runtimes (GraalVM native image, JVM + AOT cache) from the same source.
How it stacks up
| Nucleus | Electron | Tauri | CMP default | |
|---|---|---|---|---|
| Language(s) | Kotlin | JS + Node (+ C++ for natives) | JS + Rust | Kotlin |
| UI tech | Compose + Skia GPU | Chromium (Blink + V8) | OS WebView | Compose + Skia GPU |
| OS APIs | 30+ Kotlin modules, single process | Node child_process / native modules | Rust commands over IPC | Limited (Tray, Notification, no decorated window) |
| Packaging formats | 16 (DMG, PKG, NSIS, MSI, AppX, Portable, DEB, RPM, AppImage, Snap, Flatpak, ZIP, TAR, 7Z) | 5–7 via electron-builder | 5 via tauri-bundler | 6 (DMG, PKG, MSI, EXE, DEB, RPM) |
| Auto-update | Built-in (updater-runtime) | electron-updater | Tauri Updater plugin | None |
| Cold start | ~0.5 s (GraalVM) · ~1.0 s (JVM+AOT) | 2–3 s | < 1 s | 1–2 s |
| RAM idle | 60–150 MB | 200–500 MB | 50–80 MB | 200 MB |
| Binary size | 38 MB (GraalVM) · ~120 MB (JVM) | 150–200 MB | 5–20 MB | 80–120 MB |
| Native window decorations | Yes — Liquid Glass, Fluent, Yaru, Jewel | Limited (Chrome chrome) | Yes (OS chrome) | Limited |
| Mindset | One language end-to-end | Two runtimes, IPC bridge | Web frontend + Rust backend | One language, fewer batteries |
One language vs four
Electron and Tauri force a polyglot reality. You write your UI in JavaScript, your native bits in Rust or C++ or Swift, glue them with an IPC bridge, and split your team across mindsets. Nucleus stays in Kotlin top to bottom — UI, business logic, OS calls, packaging — same call graph, same memory model, same debugger.
When you do need to drop down — embed a SwiftUI view, call into Win32 directly, hit a Linux-only D-Bus interface — the Tao backend exposes NativeView, and native-access gives you typed FFI without leaving Kotlin source.
Where each tool wins
- Electron — by far the deepest ecosystem and the biggest hiring pool. Pick it when shipping speed and JS familiarity matter more than RAM, binary size, or native feel.
- Tauri — the smallest binaries on the list. Pick it when you accept the platform-specific WebView and the Rust/JS context switch.
- vanilla CMP — Nucleus's foundation. Pick it when you want Compose without the additional surface area Nucleus brings (and you'll write your own packaging, signing, updater, decorated window code on top).
- Nucleus — pick it when you want one language top-to-bottom, native window decorations, the full JVM ecosystem in-process, and a packaging pipeline that already covers 16 formats and four stores.
Drill-down comparisons
- Packaging — 16 formats vs the rest
- Nucleus vs Electron
- Nucleus vs Tauri
- Nucleus vs vanilla Compose Multiplatform
Notes
The performance numbers above are typical for a Hello-World class app. Real-world cold start and RAM scale with what your app loads. Nucleus has two runtime targets — pick GraalVM native image for cold start and binary size, JVM + AOT cache for throughput; see performance for the full story. [FACT-CHECK NEEDED] on the Electron/Tauri figures — sourced from public benchmarks.