Deno Desktop: Web Apps as Native Binaries

Deno 2.9 (currently in canary) introduces deno desktop, a tool that compiles any Deno project—from a single TypeScript file to a full Next.js app—into a redistributable desktop binary. The binary bundles your code, the Deno runtime, and a web rendering engine into one package per platform.

Why This Matters

Web technology is the most widely-known UI toolkit, but existing desktop solutions have tradeoffs. Electron binaries are huge. Tauri lacks Node compatibility and framework integration. Deno Desktop aims to be small by default, with full Node compatibility via Deno's Node compat layer, and lets you opt into a bundled Chromium (CEF) backend for identical rendering across macOS, Windows, and Linux.

Framework Auto-Detection

Point deno desktop at a Next.js, Astro, Fresh, Remix, Nuxt, SvelteKit, SolidStart, TanStack Start, or Vite SSR project and it runs the production server in release mode, or the dev server with hot reload under --hmr. No code changes required.

In-Process Bindings

Backend and UI communication goes through in-process channels, not socket-based IPC. Values are encoded as they cross the call boundary, but there's no cross-process round-trip between Deno code and the webview. This means lower latency and simpler architecture.

Cross-Compile from One Machine

The same machine can build for macOS, Windows, and Linux. Backends are downloaded as needed—no need to build on each target.

Built-in Auto-Update

Ship a single latest.json manifest and bsdiff patches. The runtime polls, applies patches, and rolls back automatically on failed launches.

Hello, Desktop

Create a one-file desktop app:

// main.ts
Deno.serve(() =>
  new Response(&#34;<h1>Hello, desktop</h1>&#34;, {
    headers: { &#34;content-type&#34;: &#34;text/html&#34; },
  })
);

Compile and run:

&gt;_./main      # macOS / Linux
.\main.exe  # Windows

Deno.serve() automatically binds to the address the webview navigates to, so you don't need to pass a port or hostname.

Configuration

The desktop block in deno.json controls backends, window options, and more. For example:

{
  &#34;desktop&#34;: {
    &#34;backend&#34;: &#34;webview&#34;,
    &#34;windows&#34;: [
      {
        &#34;title&#34;: &#34;My App&#34;,
        &#34;width&#34;: 800,
        &#34;height&#34;: 600
      }
    ]
  }
}

Backends

  • WebView (default): Uses the OS's native webview. Small binaries (a few MB).
  • CEF (Chromium Embedded Framework): Bundles Chromium. Larger binary but identical rendering across platforms.
  • Raw: No built-in webview; you control the window yourself.

Windows, Menus, Tray, and More

  • Windows: Deno.BrowserWindow lifecycle, multiple windows, events.
  • Menus: Application and context menus.
  • Tray and dock: System status icons and macOS dock integration.
  • Dialogs: prompt(), alert(), confirm() as native popups.
  • Notifications: Native OS notifications via the Web Notification API.
  • DevTools: Unified DevTools attached to both the Deno runtime and the webview.

Hot Module Replacement

--hmr enables hot reload for framework and non-framework apps.

Distribution

Cross-compilation outputs formats like .app, .exe, and .deb. Installers are in the roadmap.

Comparison to Electron, Tauri, Electrobun

Deno Desktop is opinionated: small binaries, full Node compatibility, framework auto-detection, in-process bindings, cross-compilation, and built-in auto-update. It's not a direct competitor to Electron or Tauri—it's a Deno-native solution that leverages the runtime's capabilities.

Try It Now

deno desktop ships in Deno v2.9.0 and is not stable yet. To try it, run deno upgrade canary. The command, configuration keys, and TypeScript APIs may still change before stable release.

Next Steps

  • Install Deno canary: deno upgrade canary
  • Create a main.ts with Deno.serve()
  • Run deno desktop (command may change)
  • Check the Deno Desktop docs for configuration details.