Skip to content
JDesk
Java 25 core · System WebView · Open source

Desktop apps with a Java core and a web UI.

JDesk pairs a Java 25 application core with the operating system's own WebView — WebView2, WKWebView, WebKitGTK. The Tauri development model, without Rust, without bundled Chromium.

$ npm create jdesk-app@latest my-app

Requires JDK 25+ and your platform’s system WebView.

invokeresultWeb frontendindex.html · WebViewJDeskGreet→ Hello, JDesk!window: mainJava core@DesktopCommandgreet(req, ctx) {var name =req.name();return "Hello, "}⟳ virtual thread
noncehelloinvokeresult
Why JDesk

The small-native trade-off, made for Java teams.

Keep business logic, system integration, lifecycle, and packaging in Java. Build the UI with React, Vue, Svelte, or plain HTML. Ship a small native app.

No bundled Chromium

Render in the WebView already on the machine — WebView2, WKWebView, WebKitGTK. Apps stay small instead of shipping 100+ MB of browser.

No Rust to learn

Small binaries come from a trimmed JVM runtime image via jlink, not a new systems language. If your team knows Java and Gradle, you're ready.

No Node at runtime

The frontend is static files served over the jdesk://app/ scheme. There is no local web server in production, and Node is only a build-time tool.

Compile-time typed IPC

An annotation processor discovers @DesktopCommand methods and generates a typed TypeScript client. No runtime reflection, no glue that drifts.

Secure by default

Every command needs an explicit capability grant. Navigation is locked to the app origin, popups denied, path traversal rejected — enforced in Java.

Native packaging built in

jlink + jpackage produce DMG/PKG, MSI/EXE, and DEB/RPM, each with SHA-256 checksums and a CycloneDX SBOM. Verified on real system WebViews.

One round trip

Call Java from the web. Get a typed record back.

Annotate a method with @DesktopCommand and JDesk generates a typed client for it. The frontend invokes; the handler runs on a virtual thread, off the UI thread; exactly one result crosses back — correlated by request id.

  • Deny-by-default capability check runs before your code.
  • Handlers block freely on virtual threads — no async plumbing.
  • The generated TypeScript client keeps types in sync at compile time.
GreetingService.java
@DesktopCommand("greeting.greet")
@RequiresCapability("greeting:use")
public CompletionStage<Response> greet(Request req, InvocationContext ctx) {
    String name = req.name().isBlank() ? "world" : req.name().strip();
    return completedFuture(new Response("Hello, " + name + "!"));
}
ui/src/main.ts
import { commands } from "./jdesk-ts/commands";

// Fully typed — the argument and result come from your Java records.
const res = await commands.greeting.greet({ name: "Ada" });
result.textContent = res.message; // "Hello, Ada!"
How it compares

Same trade-off as Tauri, in the language you already ship.

JDesk trades Electron's one-identical-engine guarantee for small apps on each platform's native WebView. If pixel-identical rendering everywhere is a hard requirement, Electron is still the safer choice.

Comparison of JDesk, Tauri, and Electron
JDeskTauriElectron
Backend languageJava (JVM)RustNode.js
RendererSystem WebViewSystem WebViewBundled Chromium
Bundle sizeSmall (jlink runtime)SmallestLarge (100+ MB)
Runtime dependencyTrimmed JVM (bundled)NoneBundled Chromium
IPCCompile-time typedTyped commandsIPC channels
Best fitJava / JVM teamsRust / native teamsMax web-parity
Platform support

Verified on real system WebViews.

Native, packaging, security, and stress tests run on real CI runners and Apple Silicon hardware for every target.

Windows
WebView
WebView2 (Evergreen)
Minimum
Windows 10 1809+
macOS
WebView
WKWebView
Minimum
macOS 13 Ventura+
Linux
WebView
WebKitGTK 4.1
Minimum
Ubuntu 22.04+

Scaffold an app in one command.

Pick a template — basic, React, Vue, Svelte, or a structured multi-module layout — and run it on your OS.

$ npx create-jdesk-app@latest my-app