Migrate from JBR to Tao
Switch an existing Nucleus app from the AWT backend to the Tao backend and retest the platform integrations that change.
In this tutorial, you'll move an existing Nucleus app from the AWT backend
(decorated-window-jbr or decorated-window-jni) to the Tao backend
(decorated-window-tao). The DecoratedWindow and TitleBar APIs are identical on both
backends, so the move is a dependency swap and a backend flag. The rest of the tutorial
covers the integrations you need to retest afterward.
Why switch
On the same machine, running the same app as a GraalVM native image, moving from the AWT backend to Tao measurably cuts both startup time and memory:
- Startup (launch → first window): ~0.7 s → ~0.12 s, roughly 6× faster.
- RAM (private working set, idle with window open): ~155 MB → ~100 MB, about 35% lower.
Tao drops the AWT/Swing window hierarchy and its native libraries entirely — that is what removes the startup and memory overhead. Figures are from an internal Nucleus app; your results vary with app size and platform.
Before you start
- An existing app that runs on
NucleusBackend.Awt, usingdecorated-window-jbrordecorated-window-jni. - JDK 17 or later.
- Familiarity with the backend concept: a Nucleus app ships
exactly one window runtime module, and
NucleusBackendselects it.
Swap the dependency
Replace the AWT window runtime with decorated-window-tao. Keep the
nucleus.nucleus-application entry point unchanged.
dependencies {
implementation("dev.nucleusframework:nucleus.nucleus-application:2.0.7")
implementation("dev.nucleusframework:nucleus.decorated-window-jbr:2.0.7")
}dependencies {
implementation("dev.nucleusframework:nucleus.nucleus-application:2.0.7")
implementation("dev.nucleusframework:nucleus.decorated-window-tao:2.0.7")
}Switch the backend flag
Pass backend = NucleusBackend.Tao to nucleusApplication. The window content stays
identical.
nucleusApplication {
DecoratedWindow(onCloseRequest = ::exitApplication, title = "MyApp") {
TitleBar { state -> /* … */ }
MyContent()
}
}nucleusApplication(backend = NucleusBackend.Tao) {
DecoratedWindow(onCloseRequest = ::exitApplication, title = "MyApp") {
TitleBar { state -> /* … */ }
MyContent()
}
}NucleusBackend.Auto (the default) picks Tao when decorated-window-tao is on the
classpath and falls back to the AWT backend otherwise. Set the flag explicitly to pin the
choice per build.
Retest the platform integrations
The APIs above are stable across backends, but the code paths underneath change. Retest each of these after the swap:
- Drag-and-drop. Payloads arrive as
TaoDragAndDropPayloadinstead of an AWTTransferHandler. Rewrite any handler that reads AWT transfer data. - Deep links. Register with
onDeepLink { uri -> … }as before — the callback API is unchanged, only the bridge behind it differs (TaoDeepLinkBridgeon Tao). - File dialogs. Tao has no AWT, so any direct
JFileChoosercall stops working. Switch to a native file dialog library such as FileKit — see Native file dialogs, which runs on both backends. - Native views. Embedded AWT
Canvasinstances no longer work under Tao. Compose Desktop'sSwingPanelalso stops working and crashes the app at runtime, since Tao never creates the AWT/Swing window hierarchy it needs. Embed native content withNativeViewinstead. - Window placement on Linux. Wayland compositors may ignore absolute positions. See Wayland.
- Multi-window flows. These are unchanged: one
nucleusApplication { }block with oneDecoratedWindowcall per window, each exposing its ownNucleusWindow.
Compare the backends
| Concern | AWT (JBR / JNI) | Tao |
|---|---|---|
| Startup (native image) | ~0.7 s to first window | ~0.12 s to first window (~6× faster) |
| RAM (idle, window open) | ~155 MB private working set | ~100 MB private working set (~35% lower) |
| Underlying window | ComposeWindow (extends JFrame) | TaoWindow (native handle) |
| Event dispatch | AWT EDT | Tao event loop on the main thread |
unsafe accessor | unsafe.awtWindow | unsafe.taoWindow |
| Native file dialogs | AWT / Swing | FileKit (xdg portals / native panels) |
| Drag-and-drop | AWT TransferHandler | TaoDragAndDropPayload |
| Deep links | AWT / AppKit | TaoDeepLinkBridge (same onDeepLink API) |
| Native embedding | AWT Canvas | NativeView |
| Wayland | XWayland | Native |
| macOS main thread | Not required | Requires -XstartOnFirstThread |
Decide whether to keep JBR
Stay on the AWT backend when your app:
- ships a Swing-based module,
- embeds an AWT
Canvasyou have not ported toNativeViewyet, or - depends on a library that needs
ComposeWindowdirectly.
Nucleus 2.0 publishes decorated-window-jbr, decorated-window-jni, and
decorated-window-tao from the same version, so you can defer the switch and pin the
backend per build with NucleusBackend.Awt or NucleusBackend.Tao.
What's next
- Backends — how
NucleusBackendselects the window runtime. - Decorated window — the
DecoratedWindowandTitleBarAPIs on Tao. - Native file dialogs — file pickers that run without AWT.
- Wayland — Linux window placement and compositor behavior.