---
title: "Deno bringt `deno desktop` mit: WEF-basierter Unterbefehl für eigenständige Desktop-Apps mit Deno.BrowserWindow, vereinten DevTools und Cross-Compile für macOS, Windows und Linux"
description: "Deno hat `deno desktop` am 16. Juni 2026 zusammengeführt (PR #33441), einen neuen Unterbefehl, der ein Deno-Projekt in eine eigenständige Desktop-Anwendung verwandelt. Das Feature liefert das WEF-Backend (standardmäßig CEF, plus WebView und rohem winit), die Deno.BrowserWindow-API für Fenster-Lebenszyklus und native Events, Framework-Auto-Erkennung für Next, Astro, Fresh, Remix, Nuxt, SvelteKit, SolidStart, TanStack Start und Vite SSR, einen CDP-Multiplexer, der beide V8-Isolate in einer einzigen DevTools-Session anzeigt, einen Auto-Updater mit bsdiff-Patches und cross-kompilierte .app/.dmg/.exe/.AppImage-Outputs. Drei kleinere Deno-PRs landeten am selben Morgen: `deno link`/`unlink`, `deno test --shard` und ein fetch `request_builder_hook` für `x-deno-fetch-token`/`cdn-loop`-Header."
date: 2026-06-16
image: "/images/heroes/2026-06-16--deno-desktop-subcommand-wef-cef-browserwindow.png"
author: lschvn
tags: ["runtimes", "frameworks", "tooling"]
tldr:
  - "Deno hat die [PR #33441](https://github.com/denoland/deno/pull/33441) am 16. Juni 2026 zusammengeführt und damit den Unterbefehl `deno desktop` hinzugefügt. Er kompiliert ein Deno-Projekt in eine eigenständige Desktop-Anwendung, die auf WEF (WebView Engine Foundation) basiert, mit CEF (gebündeltem Chromium) als Standard-Engine, plus WebView (OS-Webview) und raw (winit, ohne Engine) als Backends. Das Feature ist in einen neuen Unterbefehl gekapselt, sodass das bestehende CLI-Verhalten unangetastet bleibt."
  - "Die Release führt die `Deno.BrowserWindow`-API für Fenster-Lebenszyklus, Größe, Position, native Menüs, Dock/Tray-Integration sowie einen `bind`/`unbind`-RPC-Kanal zum JavaScript im Webview ein, plus Framework-Auto-Erkennung für Next.js, Astro, Fresh, Remix, Nuxt, SvelteKit, SolidStart, TanStack Start und Vite SSR. `Deno.serve()` im Entry bindet sich automatisch an den Port, zu dem der Webview navigiert, über eine neue `DENO_SERVE_ADDRESS`-Umgebungsvariable."
  - "Der HMR-Modus und `--inspect` / `--inspect-brk` laufen über einen CDP-Multiplexer, der die Deno-Runtime-V8 und die CEF-Renderer-V8 als zwei Targets in einer einzigen DevTools-Session anzeigt (ein Console-Dropdown, ein Sources-Panel). Am selben Morgen landeten auch die Unterbefehle `deno link`/`unlink` ([#34359](https://github.com/denoland/deno/pull/34359)), `deno test --shard=<i>/<n>` ([#35057](https://github.com/denoland/deno/pull/35057)) und ein fetch `request_builder_hook`, der `x-deno-fetch-token`- und `cdn-loop`-Header für Cloud-Deployments injiziert ([#35088](https://github.com/denoland/deno/pull/35088))."
faq:
  - question: "Was ist `deno desktop`?"
    answer: "`deno desktop` ist ein neuer Deno-Unterbefehl, der ein Deno-Projekt in eine eigenständige Desktop-Anwendung kompiliert. Er nutzt das WEF-Backend (WebView Engine Foundation), um einen Webview zu hosten (standardmäßig CEF/gebündeltes Chromium, den OS-Webview oder ein rohes winit-Fenster ohne Web-Engine), eine neue `Deno.BrowserWindow`-API für Fenster-Lebenszyklus und native Menüs, Framework-Auto-Erkennung für Next/Astro/Fresh/Remix/Nuxt/SvelteKit/SolidStart/TanStack Start/Vite SSR, einen `--hmr`-Modus, eine vereinte `--inspect`-DevTools-Session, die sowohl die Deno-Runtime-V8 als auch die CEF-Renderer-V8 abdeckt, einen Auto-Updater mit bsdiff-Patches und Cross-Compile zu macOS .app/.dmg, Windows .exe + DLLs und Linux App-Verzeichnis/.AppImage."
  - question: "Was ist WEF und wie nutzt `deno desktop` es?"
    answer: "WEF (WebView Engine Foundation) ist das neue Backend, auf dem `deno desktop` seinen Webview ausliefert. Die Deno-CLI lädt vorgebaute WEF-Backends von `github.com/denoland/wef/releases`, pinnt die Version über die `Cargo.lock` des Projekts, verifiziert sie per SHA-256 und legt sie unter `<deno_dir>/wef/<version>/` ab. Es gibt drei Backends: `cef` (der Default, ein gebündeltes Chromium), `webview` (der Webview des Host-Betriebssystems) und `raw` (ein winit-Fenster ohne eingebettete Engine). Für die Entwicklung gegen einen lokalen WEF-Checkout zeigt die Umgebungsvariable `WEF_DEV_DIR` die CLI auf dieses Verzeichnis statt herunterzuladen."
  - question: "Kann ich eine Desktop-App aus einem bestehenden Next.js-, Nuxt- oder SvelteKit-Projekt bauen?"
    answer: "Ja. `deno desktop` liefert eine Framework-Auto-Erkennung mit (die Implementierung lebt in `cli/tools/framework.rs`) für Next.js, Astro, Fresh, Remix, Nuxt, SvelteKit, SolidStart, TanStack Start und Vite SSR. Der Produktionsserver des Frameworks läuft standardmäßig, und der Dev-Server des Frameworks läuft unter `--hmr`. `Deno.serve()` im Entry bindet sich automatisch an den Port, zu dem der Webview navigiert, über die neue `DENO_SERVE_ADDRESS`-Umgebungsvariable, sodass die normale `port`-Konfiguration eines Frameworks weiterhin auf den Framework-Default zeigen kann."
  - question: "Unterstützt `deno desktop` Hot Module Reload?"
    answer: "Ja, über das Flag `--hmr`. Für erkannte Framework-Projekte führt `--hmr` den Dev-Server des Frameworks aus (Next-Dev-Server für Next, Nuxt-Dev-Server für Nuxt, Vite-Dev-Server für Vite SSR usw.). Für Nicht-Framework-Projekte nutzt die CLI einen File-Watcher plus einen CDP-`Debugger.setScriptSource`-Hot-Swap, um Änderungen in das laufende V8-Isolat zu schieben, während die Runtime und der CEF-Prozess am Leben bleiben. Icon-Sets werden unter `--hmr` noch nicht unterstützt; nur ein einzelner Icon-Pfad funktioniert in diesem Modus."
  - question: "Was ist sonst noch am selben Morgen in Deno main gelandet?"
    answer: "Drei weitere Features landeten im selben Deno-`main`-Branch am 16. Juni 2026, alle im Zeitfenster 06:59 bis 07:15 UTC: `deno link <path>` und `deno unlink <path-or-name>` ([PR #34359](https://github.com/denoland/deno/pull/34359)) geben einen erstklassigen CLI-Zugriff auf das `links`-Array in `deno.json` (den npm-link-artigen Workflow für lokale JSR-Pakete), mit einem `deno add ./local-dir`-Hinweis, der auf `deno link` verweist, wenn der Spec zu einem linkbaren Verzeichnis auflöst. `deno test --shard=<i>/<n>` ([PR #35057](https://github.com/denoland/deno/pull/35057)) teilt einen Testlauf auf CI-Maschinen mit stabiler Sortierung auf. Ein fetch `request_builder_hook` ([PR #35088](https://github.com/denoland/deno/pull/35088)) injiziert `x-deno-fetch-token`- und `cdn-loop`-Header für Cloud-Deployments und entfernt vom Nutzer gelieferte Kopien von `x-deno-fetch-token`, sodass Nutzercode den Runtime-Wert nicht spoofen kann."
  - question: "Welche Plattformen werden von `deno desktop` noch nicht unterstützt?"
    answer: "Mehrere Features degradieren auf einer Teilmenge von Plattformen gracefully: Auto-Update (bsdiff-Dylib-Swap und Rollback) ist unix-only und ein No-Op auf Windows; NAPI-Native-Addon-Support ist unix-only (das `promote_dylib_symbols_to_global`-Re-`dlopen` ist `#[cfg(unix)]`); Notification-Permissions sind macOS-spezifisch; Linux ist X11-only (der generierte Launcher erzwingt `--ozone-platform=x11`, Wayland läuft über XWayland); `Deno.dock` ist macOS-only. Code-Signing ist implementiert (macOS, Ad-hoc-Fallback für unsignierte Builds), aber Notarisierung und Stapling über `notarytool` sind noch nicht verkabelt. Windows-MSI-Installer, Linux-.deb/.rpm-Installer, Clipboard und secureStorage sind ebenfalls noch TODO."
---

[Deno hat `deno desktop`](https://github.com/denoland/deno/pull/33441) am 16. Juni 2026 zusammengeführt (PR #33441, [ursprünglich im April 2026 als Issue #3234](https://github.com/denoland/deno/issues/3234) eröffnet), einen neuen Unterbefehl, der ein Deno-Projekt in eine eigenständige Desktop-Anwendung kompiliert. Am selben Morgen landeten auch drei kleinere PRs: [`deno link` / `deno unlink`](https://github.com/denoland/deno/pull/34359) für das `links`-Array in `deno.json`, [`deno test --shard`](https://github.com/denoland/deno/pull/35057) zum Aufteilen eines Testlaufs auf mehrere Maschinen und ein fetch [`request_builder_hook`](https://github.com/denoland/deno/pull/35088) für Cloud-Deployments. Die Schlagzeile ist der Desktop-Unterbefehl: Er gibt Deno einen erstklassigen Pfad, mit einer einzigen `deno desktop <entry>`-Invocation plattformübergreifende Desktop-Apps auszuliefern, und die Implementierung ist der größte einzelne Zusatz zur Deno-CLI seit [Deno 2.7 die Temporal-API und Windows-on-Arm-Builds stabilisiert hat](/articles/2026-04-07-deno-2-7-stabilizes-temporal-api-windows-arm-npm-overrides).

## Was `deno desktop` tatsächlich tut

`deno desktop <entry>` kompiliert ein Deno-Projekt in eine eigenständige Desktop-Anwendung, die auf WEF (WebView Engine Foundation) aufsetzt. Die CLI lädt vorgebaute WEF-Backends von `github.com/denoland/wef/releases`, pinnt die Version über die `Cargo.lock` des Projekts, verifiziert sie per SHA-256 und legt sie unter `<deno_dir>/wef/<version>/` ab. Für die Entwicklung gegen einen lokalen WEF-Checkout zeigt `WEF_DEV_DIR` die CLI auf ein lokales Verzeichnis statt herunterzuladen.

Es gibt drei Backends, pro Projekt wählbar:

- `cef`, der Default, ein gebündeltes Chromium (CEF ist die gleiche Engine-Familie, auf der der Electron-Renderer aufsetzt).
- `webview`, der Webview des Host-Betriebssystems (Edge WebView2 auf Windows, WKWebView auf macOS, WebKitGTK auf Linux).
- `raw`, ein winit-Fenster ohne eingebettete Engine, für Projekte, die selbst in das Fenster zeichnen wollen.

`Deno.serve()` im Entry bindet sich automatisch an den Port, zu dem der Webview navigiert, über eine neue `DENO_SERVE_ADDRESS`-Umgebungsvariable, die die Desktop-Runtime injiziert. Ein Framework-Projekt kann seine normale `port`-Konfiguration behalten und das Binding der Desktop-Runtime überlassen.

## Framework-Auto-Erkennung und HMR

Die CLI erkennt Framework-Projekte in [`cli/tools/framework.rs`](https://github.com/denoland/deno/pull/33441/files) automatisch, mit erstklassiger Unterstützung für Next.js, Astro, Fresh, Remix, Nuxt, SvelteKit, SolidStart, TanStack Start und Vite SSR. Ein erkanntes Framework-Projekt bekommt standardmäßig den Produktionsserver des Frameworks; unter `--hmr` läuft stattdessen der Dev-Server des Frameworks (Next-Dev-Server für Next, Nuxt-Dev-Server für Nuxt, Vite-Dev-Server für Vite SSR usw.).

Nicht-Framework-Projekte bekommen unter `--hmr` trotzdem Hot-Reload, aber über einen anderen Mechanismus. Die CLI nutzt einen File-Watcher plus einen CDP-`Debugger.setScriptSource`-Hot-Swap, um Änderungen in das laufende V8-Isolat zu schieben, während die Deno-Runtime und der CEF-Prozess am Leben bleiben. Der praktische Effekt ist derselbe: Datei editieren, Änderung sehen, das Fenster lädt nicht neu. Die Asymmetrie ist, dass Framework-Projekte die HMR-Pipeline des Frameworks bekommen, die normalerweise granularer ist (Component-scoped Updates, Fast-Refresh-Grenzen, Framework-Level-State-Preservation), während Nicht-Framework-Projekte einen V8-Script-Level-Hot-Swap bekommen. Der Trade-off ist in der PR dokumentiert: Icon-Sets werden im `--hmr`-Modus noch nicht unterstützt, nur ein einzelner Icon-Pfad funktioniert in diesem Modus.

## Deno.BrowserWindow und die native API-Oberfläche

Die neue `Deno.BrowserWindow`-API (deklariert in `cli/tsc/dts/lib.deno.desktop.d.ts`) ist das, was Nutzercode aufruft, um ein Fenster zu steuern. Die Oberfläche deckt den Fenster-Lebenszyklus ab (`show` / `hide` / `focus` / `close` / `reload`), Größe und Position, `alwaysOnTop`, Navigation, App- und Kontextmenüs, native Fenster-Handles sowie Keyboard-, Maus-, Wheel-, Resize- und Fokus-Events. Zwei nur-native Module gesellen sich dazu: `Deno.dock` (nur macOS) für die Dock-Tile-Integration und `Deno.Tray` (plattformübergreifend) für Statusbereich-Icons mit Tooltips, Dark-Mode-Varianten und Kontextmenüs.

Ein `bind`-/`unbind`-RPC-Kanal legt das JavaScript des Webview auf der Deno-Seite als `bindings.<name>()` offen, und die umgekehrte Richtung ist `executeJs` von Deno in den Webview. Die Runtime-Integration ist der Teil, der den meisten Hebel auf bestehenden JS-Code hat: `prompt()`, `alert()` und `confirm()` im Webview werden zu nativen Popups, und ungefangene Fehler zeigen einen nativen Alert mit optionalem `POST` an `desktop.errorReporting.url` für Crash-Reporting. Der Auto-Updater legt `Deno.desktopVersion` und ein `Deno.autoUpdate({ url, interval, onUpdateReady, onRollback })` offen, das `<url>/latest.json` pollt, bsdiff-Patches auf die Dylib anwendet (über `qbsdiff`), das Ergebnis für den nächsten Start staged und bei einem fehlgeschlagenen Start einen Rollback macht.

## Eine DevTools-Session, zwei V8-Isolate

Die Flags `--inspect`, `--inspect-brk` und `--inspect-wait` laufen über einen neuen [CDP-Multiplexer](https://github.com/denoland/deno/pull/33441/files) in `cli/tools/desktop_devtools.rs`, der die Deno-Runtime-V8 und die CEF-Renderer-V8 als zwei angehängte Targets in einer einzigen DevTools-Session anzeigt. Der Effekt für den Nutzer ist ein einziges Console-Dropdown (Renderer / Deno) und ein einziges Sources-Panel mit beiden Threads. Der Multiplexer spricht Chrome DevTools Protocol zum Inspector-Client und multiplexiert es auf zwei Backends, eine CDP-Verbindung zur V8 der Runtime und eine zur V8 des Renderers.

`--inspect-brk` pausiert beide Isolate beim Start (Deno über seinen eigenen Mechanismus, CEF über ein injiziertes `Debugger.enable` + `Debugger.pause` vor der Navigation). Für die meisten Desktop-Debug-Sessions ist das der Workflow: Beide pausieren, Breakpoint im Renderer setzen, Breakpoint in der Runtime setzen, Unpause, die App treiben, zwischen Threads im selben Sources-Panel steppen. Das CEF-Target ist dasselbe DevTools-Target, das Chromium nutzt, einschließlich derselben Performance-, Memory- und Network-Panels; das Deno-Target ist das Standard-Deno-V8-Target mit `deno_core`-Introspection.

## Cross-Compile und Distribution

Die Flags `--target` und `--all-targets` laden vorgebaute `denort`-Binaries und WEF-Backends für das Ziel-Triple herunter. Die Outputs sind:

- macOS: ein `.app`-Bundle (Framework unter `Contents/Frameworks/`), mit `.dmg` produziert via `hdiutil`.
- Windows: eine `.exe` plus ein DLLs-Verzeichnis.
- Linux: ein App-Verzeichnis und ein `.AppImage` produziert via `appimagetool`.

Code-Signing ist auf macOS implementiert via den `macos.codesignIdentity`-Key in `deno.json` (mit Ad-hoc-Signatur-Fallback für unsignierte Builds), aber Notarisierung und Stapling via `notarytool` sind noch nicht verkabelt. Windows-MSI-Installer, Linux-`.deb`/`.rpm`-Installer, Clipboard und secureStorage sind in der PR-Beschreibung ebenfalls noch als TODO markiert.

## OS-spezifische Limits, die man vorab kennen sollte

Die PR-Beschreibung ist ungewöhnlich explizit zu den Lücken. Sechs Limitierungen werden als "degradieren gracefully" markiert, sind es aber wert, sie zu kennen:

- Auto-Update ist unix-only. `apply_pending_update`, `get_dylib_path` und `AutoUpdateState` sind `#[cfg(unix)]`, sodass auf Windows der Staged-Update-, bsdiff- und Rollback-Pfad ein No-Op ist.
- NAPI-Native-Addon-Support ist unix-only. `promote_dylib_symbols_to_global` (das Re-`dlopen` mit `RTLD_GLOBAL`, das NAPI-Symbole für Addons wie `next-swc` sichtbar macht) ist `#[cfg(unix)]`; auf Windows können Frameworks, die Native-Addons laden, diese möglicherweise nicht laden.
- Notification-Permissions sind macOS-spezifisch. Das LAUFEY-Backend wird via `disclaim_spawn` gestartet (posix_spawn mit disclaimter TCC-Verantwortung), sodass es sein eigener Permission-Principal wird; ohne das schlägt `UNUserNotificationCenter.requestAuthorization` fehl.
- Linux ist X11-only. Der generierte Launcher erzwingt `--ozone-platform=x11` und `GDK_BACKEND=x11`, weil der LAUFEY-Mouse/Focus/Resize-Event-Monitor XI2 auf X11 nutzt. Auf Wayland-Sessions läuft er über XWayland; natives Wayland wird nicht unterstützt.
- `Deno.dock` ist macOS-only.
- Icon-Sets werden im `--hmr`-Modus nicht unterstützt (jede Plattform).

Die Motivation, mit diesen Lücken auszuliefern, ist dieselbe wie bei jeder "wir liefern den ersten Cut, dokumentieren die Limits"-Release: Der Desktop-Unterbefehl ist das erste Mal, dass Deno eine Non-Server-Runtime ausliefert, und die WEF-Integration, die `Deno.BrowserWindow`-API, die Framework-Auto-Erkennung, die vereinten DevTools, der Auto-Updater und das Cross-Compile auf mindestens einer Plattform (macOS) zum Laufen zu bekommen, ist die Voraussetzung für alles andere. Die Cross-Plattform-Lücken sind real, aber sie sind Lücken im ersten Cut, nicht Lücken in der Architektur.

## Die drei anderen PRs vom selben Morgen

Im selben Deno-`main`-Branch sahen drei weitere Features zwischen 06:59 und 07:15 UTC landen, vor `deno desktop` um 10:41 UTC. Sie sind kleiner im Scope, aber alle primärquellenverifiziert auf derselben Release und runden die Morgengeschichte "Deno fügt einiges an Plumbing hinzu" ab.

[`deno link` und `deno unlink`](https://github.com/denoland/deno/pull/34359) geben einen erstklassigen CLI-Zugriff auf das `links`-Array in `deno.json`, das der User-Facing-Weg war, ein lokales JSR-Paket statt einer Registry-Version zu nutzen, aber bis jetzt keine CLI zur Manipulation hatte. `deno link <path>` validiert den Pfad, hängt den relativen Pfad an `links` an (erstellt das Array, falls es fehlt, und bewahrt die Formatierung über die bestehende CST-Maschinerie) und führt install aus. `deno unlink <path-or-name>` entfernt einen Eintrag per literalem Pfad, per aufgelöstem Pfad oder per JSR-Namen des gelinkten Pakets, der aus dem `deno.json` des Ziels gelesen wird. Wenn kein Argument passt, exit-et `unlink` mit Non-Zero, sodass ein Tippfehler aus Scripts und CI erkennbar ist. Als Discoverability-Fix bail-en `deno add ./local-dir` und `deno install ./local-dir` jetzt mit einem "Did you mean `deno link ./local-dir`?"-Hinweis, wenn der Spec zu einem linkbaren Verzeichnis auflöst.

[`deno test --shard=<i>/<n>`](https://github.com/denoland/deno/pull/35057) bringt CI-Sharding im Stil von Vitest / Jest / Playwright zu `deno test`. Die entdeckten Testdateien werden für eine stabile Reihenfolge sortiert, dann in `<n>` konsekutive, balancierte Gruppen aufgeteilt, und nur die Dateien für `<i>` werden ausgeführt. Jede Datei landet in genau einem Shard, Gruppengrößen unterscheiden sich um höchstens eins, und die Auswahl passiert vor jedem `--shuffle`, sodass ein gegebener Shard dieselben Dateien auf jeder Maschine ausführt, unabhängig vom Shuffle-Seed. Die PR ist explizit zum Trade-off: Der Shard wird zur Laufzeit ausgewählt, nachdem der Module-Graph der gesamten Suite bereits gebaut und type-checked wurde, sodass jede Maschine immer noch die Graph-Build- und Type-Check-Kosten für die gesamte Suite zahlt. Den Shard-Prefilter vor das Type-Checking zu verschieben, sodass jede Maschine nur ihr eigenes Subset lädt und checkt, ist ein natürlicher Follow-up.

Der [fetch `request_builder_hook`](https://github.com/denoland/deno/pull/35088) liest die Umgebungsvariablen `X_DENO_FETCH_TOKEN` und `CDN_LOOP` einmal aus und injiziert sie, falls vorhanden, als `x-deno-fetch-token`- und `cdn-loop`-Header in jeden ausgehenden `fetch()` (sowohl im Main-Worker als auch in Web-Workern). Der `cdn-loop`-Header ermöglicht es der Upstream-Infrastruktur, Request-Loops zu erkennen. Um den Fetch-Token vertrauenswürdig zu halten, wird jeder vom Nutzer gelieferte `x-deno-fetch-token`-Header entfernt, bevor der Runtime-Wert angewendet wird, sodass Nutzercode ihn nicht spoofen kann. Wenn keine der beiden Env-Vars gesetzt ist, werden keine zusätzlichen Header hinzugefügt. Das ist die Runtime-Seite desselben Cloud-Deployment-Plumbings, das das Deno-Deploy-Produkt nutzt, um zu identifizieren, welches Deployment einen ausgehenden Call gemacht hat.

## Was als Nächstes kommt

Das Vier-PR-Cluster ist ein starkes Signal der Richtung, in die Deno geht: ein `main`, der Desktop als erstklassiges Target behandelt, CI-Sharding-Parität mit Vitest / Jest / Playwright hinzufügt, den npm-link-artigen Local-Package-Workflow finalisiert und die Runtime-Level-Fetch-Header exponiert, die Cloud-Deployments brauchen. Die nächste Deno-Release (vermutlich 2.8.4, da die [Deno 2.8 Release Notes](/articles/2026-06-01-deno-2-8-audit-fix-ci-pack-subcommands) am 1. Juni erschienen) ist die erste Chance, dass diese Features in einem getaggten Build landen. Die `deno desktop`-PR war die letzte der vier, die landete, und sie ist die mit der größten zu validierenden Oberfläche, also ist der erste getaggte Build, der alle vier ausliefert, auch der, gegen den man Feedback einreichen sollte.
