---
title: "Deno 2.9 bringt 1,98x schnelleren Cold Start, 2,2–3,1x weniger RSS unter Last, npm Minimum Release Age als Default, No-Downgrade Trust Policy und eingebaute Snapshot-Tests"
description: "Deno 2.9 (Bartek Iwańczuk, veröffentlicht am 2026-06-25 auf deno.com/blog/v2.9) ist das größte Deno-Release des Zyklus. Der Cold Start sinkt von 34,2 ms auf 17,3 ms (1,98x), der Spitzen-RSS auf der Deno.serve-Realworld-Last fällt um den Faktor 2,2 (142 MB → 64 MB) und um 3,1x bei 1-MiB-Bodies (197 MB → 63 MB), und der Deno.serve-Durchsatz steigt um 1,27x in Realworld (56,8k → 72,4k req/s), 1,11x in Plaintext und 1,18x bei 1-MiB-Bodies. Supply-Chain-Härtung: Das npm Minimum Release Age wird standardmäßig mit einem 24-Stunden-Fenster aktiviert (PR #35458), und eine neue opt-in No-Downgrade Trust Policy (PR #34927) weigert sich, jede Version aufzulösen, deren Vertrauensbeweis (Staged Publishing, Trusted Publishing, Provenance-Attestation) schwächer ist als der stärkste Beweis einer zuvor veröffentlichten Version desselben Pakets. Test-Runner-Parität: eingebautes t.assertSnapshot() (#35139), Deno.test.each (#34938), --shard für CI-Fan-out (#35057), Retry und Repeats (#35053), Change-Aware --changed und --related (#35199) und Coverage-Thresholds (#35056). Lockfile-Interop: deno install seedet deno.lock aus package-lock.json, pnpm-lock.yaml, yarn.lock oder bun.lock (#34296, #35330, #35346, #35350, #35394), pnpm-workspace.yaml migriert automatisch in deno.json / package.json (#34993), und Git-Merge-Konflikt-Marker in deno.lock lösen sich automatisch auf (#34726). Dazu: deno desktop verlässt den experimentellen Status (PR #33441 vom 16. Juni), Subcommands deno link / deno unlink / deno list / deno watch, stabiles --unsafe-proto (#34738), Web Locks API (#31166), Happy Eyeballs v2 (RFC 8305) (#31726), navigator.userAgentData (#34743), der WebCrypto Modern Algorithms-Vorschlag (ML-KEM, ML-DSA, SLH-DSA, ChaCha20-Poly1305, SHA-3-Familie, KMAC, Argon2) (#34447, #34448, #34914, #35223), Node-26.3.0-Kompatibilität (#34746, #34747), Node-API v10 (#35270) und CSS-Modul-Importe unter --unstable-raw-imports (#35093). Über 165 PRs landen in diesem Zyklus."
date: 2026-06-26
image: "/images/heroes/2026-06-26--deno-2-9-cold-start-supply-chain-tests.png"
author: lschvn
tags: ["runtimes", "security", "performance"]
tldr:
  - "Deno 2.9 ([deno.com/blog/v2.9](https://deno.com/blog/v2.9), veröffentlicht am 2026-06-25 von Bartek Iwańczuk) ist das größte Deno-Release des Zyklus. Der Cold Start sinkt von 34,2 ms auf 17,3 ms (1,98x), der Spitzen-RSS auf Deno.serve fällt um 2,2x in Realworld (142 MB → 64 MB) und um 3,1x bei 1-MiB-Bodies (197 MB → 63 MB), und der Deno.serve-Durchsatz steigt um 1,27x in Realworld (56,8k → 72,4k req/s), 1,11x in Plaintext, 1,18x bei 1-MiB-Bodies. Die Perf-Arbeit umfasst Lazy-Loading der node:-Globals aus dem Snapshot, Gating des Node-Bootstraps auf Node-Worker, einen V8-Codecache für träge geladenes ESM, einen minifizierten Snapshot (#34450, #35373, #35338, #35183), einen Deno-eigenen HTTP/1.1-Serving-Pfad (#34446) und Rust-Ports von crypto.subtle (#34966) und console / Deno.inspect (#35087)."
  - "Die Supply-Chain-Härtung ist das andere Hauptthema. Das npm Minimum Release Age wird standardmäßig mit einem 24-Stunden-Fenster aktiviert ([PR #35458](https://github.com/denoland/deno/pull/35458)), sodass eine frisch veröffentlichte, potenziell kompromittierte Version nie im Moment ihres Erscheinens in den Abhängigkeitsbaum landet. Eine neue opt-in No-Downgrade Trust Policy ([PR #34927](https://github.com/denoland/deno/pull/34927)) reiht jede Paketversion nach Vertrauensbeweis (Staged Publishing, Trusted Publishing, Provenance-Attestation) ein und weigert sich, eine Version aufzulösen, deren Beweis schwächer ist als der stärkste einer zuvor veröffentlichten Version, in derselben Form wie [der s1ngularity-Angriff vom August 2025](https://socket.dev/blog/npm-package-changelog-s1ngularity-nx-attack), den [der Axios-npm-Supply-Chain-Angriff](/articles/2026-03-31--axios-npm-supply-chain-attack) und [der Red-Hat/Shai-Hulud-npm-Angriff](/articles/2026-06-06--npm-supply-chain-attack-red-hat-mini-shai-hulud) beide verlängert haben. Das Release löst auch Git-Merge-Konflikte in deno.lock automatisch auf (#34726) und erlaubt es Deno, beim ersten Install einen frischen deno.lock aus package-lock.json, pnpm-lock.yaml, yarn.lock oder bun.lock zu seeden (#34296, #35330, #35346, #35350, #35394), wobei pnpm-workspace.yaml automatisch nach deno.json / package.json migriert wird (#34993)."
  - "Die Test-Runner-Parität schließt die Vitest-/Jest-Funktionslücke. Der Testkontext erhält eingebautes t.assertSnapshot() im @std/testing/snapshot-Format ([PR #35139](https://github.com/denoland/deno/pull/35139)), Deno.test.each registriert einen unabhängig filterbaren Test pro Input-Zeile (#34938), --shard macht Fan-out auf eine CI-Matrix (#35057), Retry und Repeats erkennen flaky Tests (#35053), --changed und --related führen Dependency-Aware Change-Aware-Testauswahl durch (#35199), und Coverage-Thresholds liefern Exit-Code ungleich null, wenn Zeilen-, Branch- oder Function-Coverage unter das Ziel fällt (#35056). Der Deno-Desktop-Subcommand, der am 16. Juni als PR landete ([Artikel](/articles/2026-06-16--deno-desktop-subcommand-wef-cef-browserwindow), [PR #33441](https://github.com/denoland/deno/pull/33441)), erscheint in 2.9 als erstes getaggtes Build mit dem Feature, dazu die Subcommands deno link / deno unlink / deno list / deno watch, stabiles --unsafe-proto (#34738), Web Locks API (#31166), Happy Eyeballs v2 (#31726), navigator.userAgentData (#34743), der WebCrypto Modern Algorithms-Vorschlag (ML-KEM, ML-DSA, SLH-DSA, ChaCha20-Poly1305, SHA-3, KMAC, Argon2) (#34447, #34448, #34914, #35223), Node-26.3.0-Kompatibilität (#34746, #34747), Node-API v10 (#35270), CSS-Modul-Importe unter --unstable-raw-imports (#35093), deno fmt neu aufgebaut auf lax-markup / lax-css / lax-sql, deno compile --bundle und --include-as-is, deno bundle --declaration, deno task mit Input-basiertem Cache, JSR-Deps in node_modules, preferPackageJson und Workspace-node_modules mit .bin."
faq:
  - question: "Was ist die Schlagzeile in Deno 2.9?"
    answer: "Deno 2.9 hat drei ungefähr gleichwertige Schlagzeilen. Die Performance-Arbeit senkt den Cold Start auf 17,3 ms (1,98x), reduziert den Spitzen-RSS auf Deno.serve um 2,2 bis 3,1x und hebt den Deno.serve-Durchsatz je nach Last um 1,11x bis 1,27x, der größte Einzelzyklus-Perf-Gewinn seit Deno 1.x. Die Supply-Chain-Härtung aktiviert das npm Minimum Release Age standardmäßig mit einem 24-Stunden-Fenster und ergänzt eine opt-in No-Downgrade Trust Policy, die sich weigert, eine Paketversion aufzulösen, deren Vertrauensbeweis schwächer ist als der stärkste einer zuvor veröffentlichten Version desselben Pakets. Die Test-Runner-Arbeit schließt die Vitest-/Jest-Funktionslücke mit eingebauten Snapshot-Tests, Deno.test.each, --shard, Retry und Repeats, --changed und --related sowie Coverage-Thresholds. Dazu kommt der [deno-desktop-Subcommand](/articles/2026-06-16--deno-desktop-subcommand-wef-cef-browserwindow), der am 16. Juni als PR landete und in 2.9 als erstes getaggtes Build erscheint."
  - question: "Woher kommen die 1,98x Cold-Start- und 2-3x-Speicher-Gewinne?"
    answer: "Der Cold-Start-Gewinn kommt aus vier Primärquellen ([#34450](https://github.com/denoland/deno/pull/34450), [#35373](https://github.com/denoland/deno/pull/35373), [#35338](https://github.com/denoland/deno/pull/35338), [#35183](https://github.com/denoland/deno/pull/35183)): Lazy-Loading der node:-Globals aus dem Snapshot, damit der Snapshot kleiner ist, Gating des eifrigen Node-Bootstraps auf Node-Worker (die Haupt-Isolate zahlt die Bootstrap-Kosten nicht mehr für Code, der node: nie berührt), ein V8-Codecache für träge geladene ESM-Module, damit der zweite Start den Parse-and-Compile-Schritt überspringt, und ein minifizierter Snapshot. Auf macOS verkürzen verkettete Fixups zusätzliche Pre-Main-Zeit ([#35409](https://github.com/denoland/deno/pull/35409)). Die HTTP-Durchsatzgewinne kommen aus einem neuen Deno-eigenen HTTP/1.1-Serving-Pfad, der den Hyper-basierten Pfad ablöst, den Deno seit 1.x ausliefert ([#34446](https://github.com/denoland/deno/pull/34446)), und aus der Verlagerung von crypto.subtle ([#34966](https://github.com/denoland/deno/pull/34966)) und console / Deno.inspect ([#35087](https://github.com/denoland/deno/pull/35087)) von JavaScript nach Rust. Die Speicher-Planheit unter Last ist die operativ wichtigste Änderung: Ein Server, der zuvor mit der Last wuchs, liegt jetzt konstant um 62 MB, unabhängig davon, was er ausliefert, was der gleichen Maschine erlaubt, deutlich mehr gleichzeitige Deno.serve-Instanzen zu fahren."
  - question: "Was ist das npm Minimum Release Age und warum ist es jetzt standardmäßig aktiviert?"
    answer: "Das npm Minimum Release Age ist eine Deno-eigene Einstellung, die die Installation jeder npm-Paketversion verweigert, die jünger als ein konfiguriertes Alter ist. Deno lieferte die Einstellung erstmals in 2.6 aus, und die meisten Teams, die sie aktivierten, konfigurierten ein 24- bis 72-Stunden-Fenster. Das Prinzip: Eine große Klasse von npm-Supply-Chain-Angriffen lässt sich einfach durch Abwarten abfangen, weil eine bösartige Version meist innerhalb von ein bis zwei Tagen nach ihrer Veröffentlichung erkannt und wieder entfernt wird; ein 24-Stunden-Fenster weist die meisten davon beim Install zurück. In 2.9 wird die Einstellung mit einem 24-Stunden-Fenster standardmäßig aktiviert ([PR #35458](https://github.com/denoland/deno/pull/35458)). Die Vorgabe sitzt am unteren Ende der Präzedenzkette, sodass alles, was Sie explizit in `.npmrc` setzen, gewinnt (`min-release-age=72h` verlängert das Fenster, `min-release-age=0` deaktiviert vollständig). Dies ist dieselbe Verteidigung, die [pnpm in 9.x](https://pnpm.io/npmrc#minimizereleaseage) und [Bun in 1.x](https://bun.com/docs/runtime/modules#minimum-release-age) auslieferten. Deno ist der dritte große Paketmanager, der sie standardmäßig aktiviert."
  - question: "Was ist die No-Downgrade Trust Policy und wie funktioniert sie?"
    answer: "Die No-Downgrade Trust Policy ([PR #34927](https://github.com/denoland/deno/pull/34927)) ist eine opt-in-npm-Trust-Policy, die gegen Angriffe mit gestohlenen Maintainer-Tokens verteidigt. Sie reiht ein, wie jede Paketversion veröffentlicht wurde, in dieser absteigenden Reihenfolge der Stärke: Staged Publishing (ein Maintainer, der mit einer Live-2FA-Challenge freigibt), Trusted Publishing mit Provenance-Attestation, eine alleinstehende Provenance-Attestation und zuletzt eine einfache Token-Veröffentlichung. Mit `trust-policy=no-downgrade` in `.npmrc` weigert sich Deno, eine Version aufzulösen, deren Vertrauensbeweis schwächer ist als der stärkste Beweis einer zuvor veröffentlichten Version desselben Pakets, verglichen nach Veröffentlichungsdatum. Wenn ein Paket konsistent über Trusted Publishing oder mit Provenance ausgeliefert wurde und plötzlich eine spätere Version als einfache Token-Veröffentlichung erscheint (das Kennzeichen eines kompromittierten Maintainer-Tokens, wie beim s1ngularity-Vorfall im August 2025), wird die Installation zu einem harten Fehler statt zu einem stillen Downgrade. Die Policy folgt [pnpm's Design](https://pnpm.io/npmrc#trustpolicy), und Deno liefert zwei Hintertürchen, die pnpm spiegeln: `trust-policy-ignore-after` (in Minuten) überspringt die Prüfung für ältere, tatsächlich pre-Provenance-Veröffentlichungen, und `trust-policy-exclude[]=package` befreit benannte Pakete. Die Policy ist standardmäßig aus, weil Provenance und Trusted Publishing auf dem Registry weiterhin ungleichmäßig angenommen sind."
  - question: "Was gewinnt der Test-Runner in 2.9?"
    answer: "Sechs Stücke schließen die Vitest-/Jest-Funktionslücke. Eingebaute Snapshot-Tests landen im Testkontext als `t.assertSnapshot()`, im selben Format und Serializer wie `@std/testing/snapshot`, ohne Import erforderlich ([#35139](https://github.com/denoland/deno/pull/35139)). `Deno.test.each` registriert einen unabhängig filterbaren Test pro Input-Zeile und unterstützt Printf-artige Namensinterpolation (%s, %i/%d, %f, %j, %o, $key) ([#34938](https://github.com/denoland/deno/pull/34938)). `deno test --shard=index/count` teilt die entdeckten Testdateien für CI-Fan-out in balancierte Gruppen auf ([#35057](https://github.com/denoland/deno/pull/35057)). Die Optionen `retry: N` und `repeats: N` fangen flaky Tests und stabilitätssensible Tests ab, wobei ein Test, der erst nach einem Retry besteht, im Summary als flaky gemeldet wird, damit das Signal nicht still verloren geht ([#35053](https://github.com/denoland/deno/pull/35053)). `deno test --changed` und `deno test --related=path` führen Dependency-Aware Change-Aware-Testauswahl durch, die den Modulgraph über Workspace-Mitglieder hinweg traversiert und konservativ genug ist, dass Änderungen an Config, Lockfile, Import-Map oder package.json das Filtern deaktivieren ([#35199](https://github.com/denoland/deno/pull/35199)). Und Coverage-Thresholds liefern Exit-Code ungleich null, wenn Zeilen-, Branch- oder Function-Coverage unter das Ziel fällt, konfigurierbar pro Metrik in deno.json ([#35056](https://github.com/denoland/deno/pull/35056))."
  - question: "Wie funktioniert die Lockfile-Interop?"
    answer: "Beim ersten `deno install` in einem Projekt, das ein package-lock.json, pnpm-lock.yaml, yarn.lock oder bun.lock, aber kein deno.lock hat, seedet Deno einen frischen deno.lock direkt daraus und übernimmt die exakten aufgelösten Versionen und Integritäts-Hashes ([PRs #34296](https://github.com/denoland/deno/pull/34296), [#35330](https://github.com/denoland/deno/pull/35330), [#35346](https://github.com/denoland/deno/pull/35346), [#35350](https://github.com/denoland/deno/pull/35350), [#35394](https://github.com/denoland/deno/pull/35394)). Es gibt keine Neuauflösung und keine überraschenden Upgrades: Die Versionen, unter denen Sie unter npm liefen, sind die Versionen, unter denen Sie unter Deno laufen. Für pnpm-Workspaces wird die separate `pnpm-workspace.yaml` automatisch nach `package.json` (oder `deno.json`) migriert, ohne Kommentare oder bestehende Felder zu stören ([#34993](https://github.com/denoland/deno/pull/34993)). Für eine `deno.lock`, die bereits Git-Merge-Konflikt-Marker aus einem verpatzten Rebase enthält, löst Deno sie nun automatisch auf, vereinigt die additiven Sektionen und nimmt bei echten Spezifizierer-Konflikten die höhere Version ([#34726](https://github.com/denoland/deno/pull/34726)). Wenn ein node_modules-Verzeichnis in Gebrauch ist, installiert die neue opt-in-Einstellung `jsrDepsInNodeModules` `jsr:`-Abhängigkeiten über JSRs npm-Kompatibilitäts-Registry hinein, analog dazu, wie pnpm und npm bereits JSR-Pakete behandeln ([#35029](https://github.com/denoland/deno/pull/35029))."
  - question: "Wie sieht deno desktop in 2.9 aus?"
    answer: "Der deno-desktop-Subcommand, der [als PR #33441 am 16. Juni merged wurde](/articles/2026-06-16--deno-desktop-subcommand-wef-cef-browserwindow), erscheint in Deno 2.9 als erstes getaggtes Build. Die Abdeckung der PR vom 16. Juni ist der Architekturteil (WEF-Backend, CEF als Default, Webview-/Raw-Alternativen, Deno.BrowserWindow-API, Framework-Auto-Erkennung für Next/Astro/Fresh/Remix/Nuxt/SvelteKit/SolidStart/TanStack Start/Vite SSR, CDP-Multiplexer für vereinheitlichte DevTools über zwei V8-Isolates, Auto-Updater mit bsdiff-Patches, Cross-Compile). Das 2.9-Release fügt die praktischen Teile hinzu, die aus der PR etwas Versandfertiges machen: Ein Default-UI-Backend webview (per [#35442](https://github.com/denoland/deno/pull/35442)), damit Binaries klein bleiben und schnell starten, natives Wayland statt XWayland auf Wayland-Systemen ([#35485](https://github.com/denoland/deno/pull/35485)), Bluetooth-Nutzungsbeschreibungen und macOS-Desktop-Info.plist-Schlüssel ([#35472](https://github.com/denoland/deno/pull/35472), [#35484](https://github.com/denoland/deno/pull/35484)), gebündelte libc++-Symbole maskiert, damit die Desktop-Runtime auf Linux dlopen-bar ist ([#35424](https://github.com/denoland/deno/pull/35424)), Linux-.deb- und .rpm-Installer-Ausgabeformate ([#35296](https://github.com/denoland/deno/pull/35296)), Windows-.msi-Installer-Ausgabeformat ([#35378](https://github.com/denoland/deno/pull/35378)), Auto-Erkennung des Vite-Frameworks ([#35470](https://github.com/denoland/deno/pull/35470)) und --compress für selbstextrahierende App-Bundles ([#35420](https://github.com/denoland/deno/pull/35420)). Das vollständige Handbuch liegt unter [docs.deno.com/runtime/manual/desktop](https://docs.deno.com/runtime/manual/desktop), und `denidian`, eine mit deno desktop gebaute Notiz-App, wird daneben als Referenzbeispiel veröffentlicht."
  - question: "Welche neuen Web-Platform-Features erscheinen in 2.9?"
    answer: "Sechs Ergänzungen. Die Web Locks API erscheint vollständig ([#31166](https://github.com/denoland/deno/pull/31166)) und erlaubt die Koordination des Zugriffs auf eine benannte Ressource über async Tasks und Worker hinweg durch `navigator.locks.request(name, async lock => { /* exklusiver Zugriff hier bis dieser Callback sich auflöst */ })`, mit Shared-vs-Exclusive-Modi, ifAvailable, steal, einem AbortSignal und `navigator.locks.query()` zur Inspektion gehaltener und ausstehender Locks. Happy Eyeballs v2 ([RFC 8305](https://www.rfc-editor.org/rfc/rfc8305)) landet in `Deno.connect` und `Deno.connectTls` ([#31726](https://github.com/denoland/deno/pull/31726)) und lässt IPv6- und IPv4-Adressen auf Dual-Stack-Netzwerken um die schnellere, zuverlässigere Verbindung konkurrieren, standardmäßig aktiv mit `autoSelectFamily: false` zum Abschalten oder `autoSelectFamilyAttemptDelay` zum Justieren des Versatzes (Standard 250 ms). `navigator.userAgentData` erscheint in Window- und Worker-Scopes ([#34743](https://github.com/denoland/deno/pull/34743)). `RequestInit` akzeptiert das Fetch-Standard-`priority`-Member (`auto`, `high`, `low`) ([#34716](https://github.com/denoland/deno/pull/34716)). `Deno.watchFs` unterstützt eine `ignore`-Option für Pfade wie `.git` oder `build`-Output ([#31582](https://github.com/denoland/deno/pull/31582)). Und `process.kill` auf den eigenen Prozess verlangt kein `--allow-run` mehr ([#34382](https://github.com/denoland/deno/pull/34382))."
  - question: "Was ist die WebCrypto-Modern-Algorithms-Arbeit in 2.9?"
    answer: "Deno 2.9 implementiert den [Modern Algorithms in the Web Cryptography API-Vorschlag](https://wicg.github.io/webcrypto-modern-algos/) und beginnt mit den Post-Quantum-Algorithmen des NIST. ML-KEM (FIPS 203) Key Encapsulation: ML-KEM-512, ML-KEM-768, ML-KEM-1024 ([#34447](https://github.com/denoland/deno/pull/34447)). ML-DSA (FIPS 204) Signaturen: ML-DSA-44, ML-DSA-65, ML-DSA-87, inklusive JWK-Import/Export ([#34448](https://github.com/denoland/deno/pull/34448), [#34914](https://github.com/denoland/deno/pull/34914)). SLH-DSA (FIPS 205) Signaturen, alle zwölf Parametersätze ([#35223](https://github.com/denoland/deno/pull/35223)). ML-KEM fügt vier neue crypto.subtle-Methoden hinzu: encapsulateKey / encapsulateBits und decapsulateKey / decapsulateBits. Über Post-Quantum hinaus ergänzt 2.9 ChaCha20-Poly1305 AEAD ([#34417](https://github.com/denoland/deno/pull/34417)), die SHA-3-Familie und XOFs (SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256, cSHAKE, TurboSHAKE, KangarooTwelve), KMAC und Argon2-Key-Derivation. Eine neue synchrone Feature-Detection-Methode `SubtleCrypto.supports()` ([#34903](https://github.com/denoland/deno/pull/34903)) erlaubt es Anwender-Code, den Support zur Laufzeit zu prüfen. Die gesamte crypto.subtle-Implementierung wurde von JavaScript auf Rust portiert ([#34966](https://github.com/denoland/deno/pull/34966)), was den Per-Call-Overhead reduziert, ohne das Verhalten zu ändern. Dies ist dieselbe Arbeit, die [der Node.js 24.18.0 'Krypton' LTS Web Crypto-Artikel](/articles/2026-06-24--node-js-24-18-krypton-lts-buffer-pool-turboshake) für Node 24 abdeckte."
  - question: "Welche Node.js-Kompatibilitätsänderungen erscheinen in 2.9?"
    answer: "Deno 2.9 verschiebt sein Node.js-Kompatibilitätsziel auf Node 26. Die gemeldete `process.version` bewegt sich auf `v26.3.0` ([#34747](https://github.com/denoland/deno/pull/34747)), und die node-compat-Testsuite, die Deno ausführt, steigt auf 26.3.0 ([#34746](https://github.com/denoland/deno/pull/34746)). Bare Node-Builtins lösen sich nun ohne Konfiguration auf: `import fs` und `import path` mappen bedingungslos auf `node:fs` / `node:path`, ohne `--unstable-bare-node-builtins`-Flag ([#33316](https://github.com/denoland/deno/pull/33316)). Dies fixt auch einen Bug, bei dem ein node_modules-Paket einen Builtin shadowen konnte; Builtins gewinnen nun immer, während `deno.json`-Imports und `package.json`-Dependency-Mappings ihre Präzedenz behalten. Hervorzuheben: `node:test` gewann `mock.module()` und `mock.timers` ([#35329](https://github.com/denoland/deno/pull/35329), [#33946](https://github.com/denoland/deno/pull/33946)), `t.assert.fileSnapshot()` ([#35478](https://github.com/denoland/deno/pull/35478)) und `TestContext.runOnly()` ([#35158](https://github.com/denoland/deno/pull/35158)) und schlägt nun bei unbehandelten Rejections fehl, erzwingt Timeouts und führt Hooks in der korrekten Reihenfolge aus ([#35297](https://github.com/denoland/deno/pull/35297), [#35393](https://github.com/denoland/deno/pull/35393)). Weitere Runtime-APIs: `process.resourceUsage()` ([#35468](https://github.com/denoland/deno/pull/35468)) und `worker_threads.isInternalThread` ([#35234](https://github.com/denoland/deno/pull/35234)) sind nun implementiert, und `AsyncLocalStorage`-Context bleibt über `node:net`-Callbacks hinweg erhalten ([#35237](https://github.com/denoland/deno/pull/35237)). Deno's NAPI-Implementierung meldet nun Version 10 ([#35270](https://github.com/denoland/deno/pull/35270)), in Einklang mit Node 26."
  - question: "Was sollten Deno-2.8-Nutzer und Node-Nutzer heute tun?"
    answer: "Deno-2.8-Nutzer sollten sofort aktualisieren: `deno upgrade` zieht 2.9 an Ort und Stelle, und die Cold-Start- und Speicher-Gewinne sind groß genug, dass jede Produktionslast profitiert. Die Supply-Chain-Defaults sind außerdem strikt besser als das vorherige Verhalten: Minimum Release Age mit 24 Stunden fängt eine Klasse von Angriffen, die der vorherige Default nicht abfing, und die No-Downgrade Trust Policy ist opt-in für Teams, die sich weiter härten wollen. Die Lockfile-Interop bedeutet, dass ein Node-Projekt mit einem einzigen `deno install` wechseln kann und einen geseedeten deno.lock direkt aus dem bestehenden package-lock.json, pnpm-lock.yaml, yarn.lock oder bun.lock bekommt, dann unverändert über `deno task` und das `node`-Shim, das Deno auf PATH legt, wenn kein echtes Node installiert ist, läuft. Teams, die auf eine Regression stoßen, können Deno mit `deno upgrade --version 2.8.3` auf eine bestimmte Version pinnen oder die Version über den Standard-Versionsmanager (z. B. `vfox`, `asdf`, `mise`) festlegen. Für Node-Nutzer ist die WebCrypto-Modern-Algorithms-Arbeit derselben Familie wie [der Node.js 24.18.0 'Krypton' LTS Web Crypto-Artikel](/articles/2026-06-24--node-js-24-18-krypton-lts-buffer-pool-turboshake), und [Node.js 26.4.0 'Current'](/articles/2026-06-25--node-js-26-4-current-vfs-loader-package-maps) nimmt dieselbe ML-DSA-/ML-KEM-/ChaCha20-Poly1305-/AES-KW-Arbeit in einer anderen Form auf; Teams, die Deno als Alternative zu Node evaluieren, haben einen Grund mehr, es sich auf einer realen Last genauer anzusehen."
---

[Deno 2.9](https://deno.com/blog/v2.9) wurde am 2026-06-25 veröffentlicht, publiziert von Bartek Iwańczuk mit [den Release-Notes auf deno.com](https://deno.com/blog/v2.9) und [dem GitHub-Releases-API-Listing v2.9.0](https://github.com/denoland/deno/releases/tag/v2.9.0). Es ist das größte Deno-Release des Zyklus und das erste getaggte Build, das den [deno-desktop-Subcommand](/articles/2026-06-16--deno-desktop-subcommand-wef-cef-browserwindow) enthält (die [PR #33441 vom 16. Juni](https://github.com/denoland/deno/pull/33441)) sowie eine lange Liste von Supply-Chain-, Performance-, Test-Runner-, Web-Platform- und Node.js-Kompatibilitätsänderungen. Der Blogpost öffnet mit drei Zahlen, die das Release verankern: Der Cold Start fällt von 34,2 ms auf 17,3 ms (1,98x), der Spitzen-Resident-Set auf Deno.serve sinkt um 2,2x bei der Realworld-Last und um 3,1x bei 1-MiB-Bodies, und der Deno.serve-Durchsatz steigt um 1,27x in Realworld, 1,11x in Plaintext und 1,18x bei 1-MiB-Bodies. Hinter diesen Zahlen stehen vier primäre Perf-Änderungen ([#34450](https://github.com/denoland/deno/pull/34450), [#35373](https://github.com/denoland/deno/pull/35373), [#35338](https://github.com/denoland/deno/pull/35338), [#35183](https://github.com/denoland/deno/pull/35183)), plus ein neuer Deno-eigener HTTP/1.1-Serving-Pfad ([#34446](https://github.com/denoland/deno/pull/34446)) und Rust-Ports von crypto.subtle ([#34966](https://github.com/denoland/deno/pull/34966)) und console / Deno.inspect ([#35087](https://github.com/denoland/deno/pull/35087)).

Das 2.9-Release folgt auf [Deno 2.8 am 1. Juni](/articles/2026-06-01--deno-2-8-audit-fix-ci-pack-subcommands), das sich auf Audit-Fixes, CI-Tooling und den `pack`-Subcommand konzentrierte. Der 2.9-Zyklus hat eine andere Form: Über 165 PRs landen, die Perf-Gewinne sind der größte Einszyklus-Sprung seit zwei Jahren, und die Supply-Chain-Arbeit schließt die Lücke zu [pnpm's `minimumReleaseAge`](https://pnpm.io/npmrc#minimizereleaseage) und [pnpm's `trustPolicy`](https://pnpm.io/npmrc#trustpolicy)-Defaults.

## Cold Start, Speicher und Durchsatz

Die Schlagzeilenzahlen kommen aus Deno's eigenem Benchmark-Harness, der drei Deno.serve-Lasten bei Concurrency 100 gegen Deno 2.8.0 auf einer dedizierten x86_64-Linux-Box ausführt, mit Server und Lastgenerator an disjunkten Cores gepinnt und oha-Median aus 3 Runs. Der Cold Start ist der Mittelwert aus 150 hyperfine-Runs eines Hello-World-Programms. Die komplette Auswahl:

| Last | Deno 2.8 | Deno 2.9 | Änderung |
| --- | --- | --- | --- |
| Cold Start (niedriger ist besser) | 34,2 ms | 17,3 ms | 1,98x schneller |
| Deno.serve Realworld (req/s, höher ist besser) | 56,8k | 72,4k | 1,27x |
| Deno.serve Plaintext (req/s) | 77,0k | 85,6k | 1,11x |
| Deno.serve 1-MiB-Body (req/s) | 1 617 | 1 907 | 1,18x |
| RSS, Realworld (niedriger ist besser) | 142 MB | 64 MB | 2,2x weniger Speicher |
| RSS, 1-MiB-Body | 197 MB | 63 MB | 3,1x weniger Speicher |

Der Cold-Start-Sturz ist die für sich genommen auffälligste Zahl. Der Gewinn kommt aus vier primären Änderungen. Erstens Lazy-Loading der `node:`-Globals aus dem Snapshot, damit der Snapshot selbst kleiner ist ([#34450](https://github.com/denoland/deno/pull/34450)). Zweitens Gating des eifrigen Node-Bootstraps auf Node-Worker, sodass die Haupt-Isolate die Bootstrap-Kosten nicht mehr für Code zahlt, der `node:` nie berührt ([#35373](https://github.com/denoland/deno/pull/35373)). Drittens ein V8-Codecache für träge geladene ESM-Module, sodass der zweite Start den Parse-and-Compile-Schritt überspringt ([#35338](https://github.com/denoland/deno/pull/35338)). Viertens ein minifizierter Snapshot, der das On-Disk-Image komprimiert ([#35183](https://github.com/denoland/deno/pull/35183)). Auf macOS verkürzen verkettete Fixups zusätzliche Pre-Main-Zeit ([#35409](https://github.com/denoland/deno/pull/35409)).

Die HTTP-Durchsatzgewinne reiten auf einem neuen Deno-eigenen HTTP/1.1-Serving-Pfad, der den Hyper-basierten Pfad ablöst, den Deno seit 1.x ausliefert ([#34446](https://github.com/denoland/deno/pull/34446)). Die beiden Rust-Ports sind kleiner, aber folgenreich: crypto.subtle ([#34966](https://github.com/denoland/deno/pull/34966)) und console / Deno.inspect ([#35087](https://github.com/denoland/deno/pull/35087)) wandern von JavaScript nach Rust und reduzieren den Per-Call-Overhead ohne Verhaltensänderung. Der WebCrypto-Port ist die Voraussetzung für [die WebCrypto-Modern-Algorithms-Arbeit](#webcrypto-modern-algorithms), die in derselben Release landet.

Die Speicher-Planheit unter Last ist die operativ wichtigste Änderung. In 2.8 wuchs die RSS mit der Last, von rund 94 MB beim Servieren von Plaintext bis zu 197 MB beim Streamen von 1-MiB-Bodies. In 2.9 bleibt sie im Wesentlichen flach, hält sich um 62 MB, unabhängig davon, was der Server tut. Das ergibt 2,2x weniger Spitzen-RSS bei der Realworld-Last und 3,1x weniger bei 1-MiB-Bodies, sodass dieselbe Maschine deutlich mehr gleichzeitige Deno.serve-Instanzen fahren kann, bevor ihr die Luft ausgeht. Das Team markiert das als das Highlight des Zyklus.

## Supply-Chain-Härtung

Die zweite Schlagzeile ist die Supply-Chain-Härtung, und sie ist der Teil von 2.9, der sich am direktesten auf [den Axios-npm-Supply-Chain-Angriff](/articles/2026-03-31--axios-npm-supply-chain-attack) von März und [den Red-Hat/Shai-Hulud-npm-Angriff](/articles/2026-06-06--npm-supply-chain-attack-red-hat-mini-shai-hulud) von Anfang Juni abbilden lässt.

**npm Minimum Release Age, standardmäßig aktiv.** [PR #35458](https://github.com/denoland/deno/pull/35458) aktiviert das Minimum Release Age standardmäßig mit einem 24-Stunden-Fenster. Die Einstellung wurde in Deno 2.6 eingeführt und war bereits dokumentiert, aber in 2.9 ist sie standardmäßig an. Das Prinzip ist einfach: Eine große Klasse von npm-Supply-Chain-Angriffen lässt sich durch Abwarten abfangen, weil eine bösartige Version meist innerhalb von ein bis zwei Tagen nach ihrer Veröffentlichung erkannt und wieder entfernt wird; ein 24-Stunden-Fenster weist die meisten davon beim Install zurück. Die Vorgabe sitzt am unteren Ende der Präzedenzkette, sodass alles, was Sie explizit in `.npmrc` setzen, gewinnt: `min-release-age=72h` verlängert das Fenster, `min-release-age=0` deaktiviert vollständig. Dies ist dieselbe Verteidigung, die [pnpm in 9.x](https://pnpm.io/npmrc#minimizereleaseage) und [Bun in 1.x](https://bun.com/docs/runtime/modules#minimum-release-age) auslieferten. Deno ist der dritte große Paketmanager, der sie standardmäßig aktiviert.

**No-Downgrade Trust Policy, opt-in.** [PR #34927](https://github.com/denoland/deno/pull/34927) ergänzt die Trust Policy, die Deno bisher fehlte. Sie reiht ein, wie jede Paketversion veröffentlicht wurde, in dieser absteigenden Reihenfolge der Stärke: Staged Publishing (ein Maintainer, der mit einer Live-2FA-Challenge freigibt), Trusted Publishing mit Provenance-Attestation, eine alleinstehende Provenance-Attestation und zuletzt eine einfache Token-Veröffentlichung. Mit `trust-policy=no-downgrade` in `.npmrc` weigert sich Deno, eine Version aufzulösen, deren Vertrauensbeweis schwächer ist als der stärkste Beweis einer zuvor veröffentlichten Version desselben Pakets, verglichen nach Veröffentlichungsdatum. Wenn ein Paket konsistent über Trusted Publishing oder mit Provenance ausgeliefert wurde und plötzlich eine spätere Version als einfache Token-Veröffentlichung erscheint (das Kennzeichen eines kompromittierten Maintainer-Tokens, wie beim s1ngularity-Vorfall im August 2025, der sich in [den Axios-npm-Supply-Chain-Angriff](/articles/2026-03-31--axios-npm-supply-chain-attack) und [den Red-Hat/Shai-Hulud-npm-Angriff](/articles/2026-06-06--npm-supply-chain-attack-red-hat-mini-shai-hulud) verlängerte), wird die Installation zu einem harten Fehler statt zu einem stillen Downgrade. Die Policy folgt [pnpm's Design](https://pnpm.io/npmrc#trustpolicy), und Deno liefert zwei Hintertürchen, die pnpm spiegeln: `trust-policy-ignore-after` (in Minuten) überspringt die Prüfung für ältere, tatsächlich pre-Provenance-Veröffentlichungen, und `trust-policy-exclude[]=package` befreit benannte Pakete. Die Policy ist standardmäßig aus, weil Provenance und Trusted Publishing auf dem Registry weiterhin ungleichmäßig angenommen sind.

**Lockfile-Interop.** Die Supply-Chain-Geschichte erstreckt sich auf Lockfiles. Beim ersten `deno install` in einem Projekt, das ein `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock` oder `bun.lock`, aber kein `deno.lock` hat, seedet Deno einen frischen deno.lock direkt daraus und übernimmt die exakten aufgelösten Versionen und Integritäts-Hashes ([#34296](https://github.com/denoland/deno/pull/34296), [#35330](https://github.com/denoland/deno/pull/35330), [#35346](https://github.com/denoland/deno/pull/35346), [#35350](https://github.com/denoland/deno/pull/35350), [#35394](https://github.com/denoland/deno/pull/35394)). Für pnpm-Workspaces wird die separate `pnpm-workspace.yaml` automatisch nach `package.json` (oder `deno.json`) migriert, ohne Kommentare oder bestehende Felder zu stören ([#34993](https://github.com/denoland/deno/pull/34993)). Für eine `deno.lock`, die bereits Git-Merge-Konflikt-Marker aus einem verpatzten Rebase enthält, löst Deno sie nun automatisch auf, vereinigt die additiven Sektionen und nimmt bei echten Spezifizierer-Konflikten die höhere Version ([#34726](https://github.com/denoland/deno/pull/34726)). Zusammengenommen bedeutet das, dass das Umschalten eines Node-Projekts auf Deno nur wenige Befehle braucht und den bestehenden Abhängigkeitsgraph exakt bewahrt.

## Test-Runner-Parität mit Vitest / Jest

Die Test-Runner-Arbeit schließt die Vitest-/Jest-Funktionslücke, die der meistgenannte Grund für Teams war, die an einem Node-gehosteten Testframework festhalten, selbst wenn sie Deno für Produktionscode mögen.

**Eingebaute Snapshot-Tests.** [PR #35139](https://github.com/denoland/deno/pull/35139) ergänzt `t.assertSnapshot()` im Testkontext, im selben Format und Serializer wie `@std/testing/snapshot`, ohne Import erforderlich. Snapshots werden in `__snapshots__/test_file.snap` neben dem Test geschrieben; bei einem Mismatch druckt der Runner einen Diff und sagt, wie man aktualisiert (`deno test --update-snapshots`). Snapshots am Standardort brauchen keine read/write-Permissions (der Runner verwaltet sie), und veraltete Einträge werden automatisch entfernt, wenn ein vollständiger Lauf sie aktualisiert. Snapshot-Testing funktioniert auch über `node:test`, via `t.assert.fileSnapshot()` ([#35478](https://github.com/denoland/deno/pull/35478)).

**Deno.test.each.** [PR #34938](https://github.com/denoland/deno/pull/34938) registriert einen unabhängig filterbaren Test pro Input-Zeile. Array-Cases werden als positionale Argumente gespreizt; Objekt-Cases werden als einzelnes Argument übergeben und können über `$key` in den Testnamen interpoliert werden. Namens-Templates unterstützen Printf-artige Tokens (`%s`, `%i`/`%d`, `%f`, `%j`, `%o`), `%#` für den Case-Index und `$key.nested` für verschachtelten Objekt-Zugriff. `Deno.test.only.each` und `Deno.test.ignore.each` komponieren sich wie erwartet.

**`deno test --shard`.** [PR #35057](https://github.com/denoland/deno/pull/35057) teilt die entdeckten Testdateien für CI-Fan-out in balancierte Gruppen auf. Es fällt direkt in eine GitHub-Actions-Matrix; der Index ist 1-basiert, Sharding passiert vor `--shuffle`, und Over-Sharding (mehr Shards als Dateien) lässt einfach manche Shards leer und beendet sauber. Der Trade-off, den die PR explizit benennt: Der Shard wird zur Laufzeit ausgewählt, nachdem der Modulgraph für die gesamte Suite gebaut und type-checked wurde, sodass jede Maschine weiterhin die Graph-Build- und Type-Check-Kosten für die ganze Suite zahlt. Den Shard-Vorfilter vor das Type-Checking zu verschieben, ist ein natürliches Follow-up.

**Retry und Repeats.** [PR #35053](https://github.com/denoland/deno/pull/35053) ergänzt die Optionen `retry: N` und `repeats: N`, entweder pro Test oder über den ganzen Lauf. Ein Test, der erst nach einem Retry besteht, wird im Summary als flaky gemeldet, damit das Signal nicht still verloren geht. Per-Test-Optionen haben Vorrang vor den CLI-Flags (inklusive einer expliziten `0`, um einen Test zu deaktivieren).

**Change-Aware-Testauswahl.** [PR #35199](https://github.com/denoland/deno/pull/35199) ergänzt `deno test --changed` (Tests, die von nicht committeten Änderungen betroffen sind), `deno test --changed=origin/main` (Tests, die seit dem Abzweigen von main betroffen sind) und `deno test --related=src/util.ts` (Tests, die von einer bestimmten Datei abhängen). Die Auswahl ist Dependency-Aware (sie traversiert den Modulgraph über Workspace-Mitglieder hinweg) und konservativ: Eine Änderung an Config, Lockfile, Import-Map oder package.json deaktiviert das Filtern und führt alles aus.

**Coverage-Thresholds.** [PR #35056](https://github.com/denoland/deno/pull/35056) lässt Coverage einen Lauf fehlschlagen lassen, wenn sie unter ein Ziel fällt, entweder per `--threshold=90` oder pro Metrik in `deno.json` konfiguriert (`lines`, `branches`, `functions`). Wenn das Aggregat zu kurz fällt, beendet der Befehl mit Exit-Code ungleich null und sagt, welche Metrik verfehlt wurde.

## deno desktop erscheint im ersten getaggten Build

Der [deno-desktop-Subcommand](/articles/2026-06-16--deno-desktop-subcommand-wef-cef-browserwindow), der [als PR #33441 am 16. Juni merged wurde](https://github.com/denoland/deno/pull/33441), erscheint in Deno 2.9 als erstes getaggtes Build mit dem Feature. Der Artikel vom 16. Juni deckt den Architekturteil ab (WEF-Backend, CEF als Default, Webview-/Raw-Alternativen, `Deno.BrowserWindow`-API, Framework-Auto-Erkennung für Next.js / Astro / Fresh / Remix / Nuxt / SvelteKit / SolidStart / TanStack Start / Vite SSR, CDP-Multiplexer für vereinheitlichte DevTools über zwei V8-Isolates, Auto-Updater mit bsdiff-Patches, Cross-Compile). Das 2.9-Release fügt die praktischen Teile hinzu, die aus der PR etwas Versandfertiges machen:

- **Default-UI-Backend ist webview** ([#35442](https://github.com/denoland/deno/pull/35442)), damit Binaries klein bleiben und schnell starten. `--backend cef` wechselt zu gebündeltem Chromium für garantiert identisches Rendering auf jeder Plattform.
- **Natives Wayland** statt XWayland auf Wayland-Systemen ([#35485](https://github.com/denoland/deno/pull/35485)). Die PR vom 16. Juni war nur X11-fähig und ließ Wayland-Sessions über XWayland laufen; der 2.9-Zyklus hebt diese Einschränkung auf.
- **Linux-.deb- und .rpm-Installer-Ausgabeformate** ([#35296](https://github.com/denoland/deno/pull/35296)), erzeugt von jedem Host ohne plattformspezifische Packaging-Toolchain.
- **Windows-.msi-Installer-Ausgabeformat** ([#35378](https://github.com/denoland/deno/pull/35378)), ebenso.
- **Auto-Erkennung des Vite-Frameworks** ([#35470](https://github.com/denoland/deno/pull/35470)), zusätzlich zur Liste Next / Astro / Fresh / Remix / Nuxt / SvelteKit / SolidStart / TanStack Start.
- **Bluetooth-Nutzungsbeschreibungen und macOS-Desktop-Info.plist-Schlüssel** ([#35472](https://github.com/denoland/deno/pull/35472), [#35484](https://github.com/denoland/deno/pull/35484)), für die Bereitschaft zur App-Store-Einreichung.
- **Gebündelte libc++-Symbole maskiert** ([#35424](https://github.com/denoland/deno/pull/35424)), damit die Desktop-Runtime auf Linux dlopen-bar ist.
- **--compress für selbstextrahierende App-Bundles** ([#35420](https://github.com/denoland/deno/pull/35420)), die sich beim ersten Start entpacken und die Artefaktgröße für npm-schwere Projekte reduzieren.

Das vollständige Handbuch liegt unter [docs.deno.com/runtime/manual/desktop](https://docs.deno.com/runtime/manual/desktop), und `denidian`, eine mit deno desktop gebaute Notiz-App, wird daneben als Referenzbeispiel veröffentlicht.

## WebCrypto Modern Algorithms

Die WebCrypto-Arbeit ist derselben Familie wie [der Node.js 24.18.0 'Krypton' LTS Web Crypto-Artikel](/articles/2026-06-24--node-js-24-18-krypton-lts-buffer-pool-turboshake) und [die Node.js 26.4.0 'Current' WebCrypto-cSHAKE-Arbeit](/articles/2026-06-25--node-js-26-4-current-vfs-loader-package-maps): der [Modern Algorithms in the Web Cryptography API-Vorschlag](https://wicg.github.io/webcrypto-modern-algos/), beginnend mit den Post-Quantum-Algorithmen des NIST.

- **ML-KEM (FIPS 203)** Key Encapsulation: ML-KEM-512, ML-KEM-768, ML-KEM-1024 ([#34447](https://github.com/denoland/deno/pull/34447)). Ergänzt vier neue `crypto.subtle`-Methoden: `encapsulateKey` / `encapsulateBits` und `decapsulateKey` / `decapsulateBits`.
- **ML-DSA (FIPS 204)** Signaturen: ML-DSA-44, ML-DSA-65, ML-DSA-87, inklusive JWK-Import/Export ([#34448](https://github.com/denoland/deno/pull/34448), [#34914](https://github.com/denoland/deno/pull/34914)).
- **SLH-DSA (FIPS 205)** Signaturen, alle zwölf Parametersätze ([#35223](https://github.com/denoland/deno/pull/35223)).
- **ChaCha20-Poly1305** AEAD ([#34417](https://github.com/denoland/deno/pull/34417)).
- **SHA-3-Familie und XOFs**: SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256, cSHAKE, TurboSHAKE, KangarooTwelve.
- **KMAC** und **Argon2**-Key-Derivation.

Eine neue synchrone Feature-Detection-Methode `SubtleCrypto.supports()` ([#34903](https://github.com/denoland/deno/pull/34903)) erlaubt es Anwender-Code, den Support zur Laufzeit zu prüfen: `SubtleCrypto.supports("sign", "ML-DSA-65")` liefert `true` auf einem 2.9-Build. Die gesamte `crypto.subtle`-Implementierung wurde von JavaScript nach Rust portiert ([#34966](https://github.com/denoland/deno/pull/34966)), was den Per-Call-Overhead reduziert, ohne das Verhalten zu ändern, und was die Voraussetzung dafür ist, dass die Post-Quantum-Arbeit in derselben Release landet.

## Node.js-Kompatibilität zieht auf 26 vor

Deno 2.9 verschiebt sein Node.js-Kompatibilitätsziel auf Node 26. Die gemeldete `process.version` bewegt sich auf `v26.3.0` ([#34747](https://github.com/denoland/deno/pull/34747)), und die node-compat-Testsuite, die Deno ausführt, steigt auf 26.3.0 ([#34746](https://github.com/denoland/deno/pull/34746)). Bare Node-Builtins lösen sich nun ohne Konfiguration auf: `import fs` und `import path` mappen bedingungslos auf `node:fs` / `node:path`, ohne `--unstable-bare-node-builtins`-Flag ([#33316](https://github.com/denoland/deno/pull/33316)). Dies fixt auch einen Bug, bei dem ein node_modules-Paket einen Builtin shadowen konnte; Builtins gewinnen nun immer, während `deno.json`-Imports und `package.json`-Dependency-Mappings ihre Präzedenz behalten.

Die `node:test`-Zugewinne sind für sich genommen ein wichtiges Stück: `mock.module()` und `mock.timers` ([#35329](https://github.com/denoland/deno/pull/35329), [#33946](https://github.com/denoland/deno/pull/33946)), `t.assert.fileSnapshot()` ([#35478](https://github.com/denoland/deno/pull/35478)) und `TestContext.runOnly()` ([#35158](https://github.com/denoland/deno/pull/35158)). Der Runner schlägt nun bei unbehandelten Rejections fehl, erzwingt Timeouts und führt Hooks in der korrekten Reihenfolge aus ([#35297](https://github.com/denoland/deno/pull/35297), [#35393](https://github.com/denoland/deno/pull/35393)). Weitere Runtime-APIs: `process.resourceUsage()` ([#35468](https://github.com/denoland/deno/pull/35468)) und `worker_threads.isInternalThread` ([#35234](https://github.com/denoland/deno/pull/35234)) sind nun implementiert, und `AsyncLocalStorage`-Context bleibt über `node:net`-Callbacks hinweg erhalten ([#35237](https://github.com/denoland/deno/pull/35237)). Deno's NAPI-Implementierung meldet nun Version 10 ([#35270](https://github.com/denoland/deno/pull/35270)), in Einklang mit Node 26. Die Web-Storage-/KV-Persistenz ([#34618](https://github.com/denoland/deno/pull/34618)) für `deno compile`-Outputs und die `preferPackageJson`-Einstellung ([#35392](https://github.com/denoland/deno/pull/35392)) sind dieselbe kompatibilitätsgetriebene Ergonomiearbeit, nun stabilisiert.

## Lockfile-Interop und Abhängigkeitsverwaltung

Die Lockfile-Arbeit ist der Teil von 2.9, der am direktesten darauf abzielt, Node-Projekten den Wechsel zu Deno zu ermöglichen. Die fünf Lockfile-lesenden PRs ([#34296](https://github.com/denoland/deno/pull/34296), [#35330](https://github.com/denoland/deno/pull/35330), [#35346](https://github.com/denoland/deno/pull/35346), [#35350](https://github.com/denoland/deno/pull/35350), [#35394](https://github.com/denoland/deno/pull/35394)) bedeuten zusammen, dass `deno install` in einem Projekt mit `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock` oder `bun.lock` einen deno.lock erzeugt, der die exakten aufgelösten Versionen und Integritäts-Hashes aus dem bestehenden Lockfile bewahrt. Es gibt keine Neuauflösung und keine überraschenden Upgrades: Die Versionen, unter denen Sie unter npm liefen, sind die Versionen, unter denen Sie unter Deno laufen. Von da an schreibt `deno install` ein `node_modules`-Verzeichnis, das Deno ausführen kann, und `deno task` führt die `package.json`-Skripte aus, die Sie bereits haben, sodass der Rest des Teams weiterarbeiten kann wie bisher.

Für pnpm-Workspaces wird die separate `pnpm-workspace.yaml` automatisch nach `package.json` (oder `deno.json`) migriert, ohne Kommentare oder bestehende Felder zu stören ([#34993](https://github.com/denoland/deno/pull/34993)). Kombiniert mit dem `catalog:`-Protokoll, das Deno in 2.8 einführte, funktionieren zentralisierte, geteilte Dependency-Versionen nach dem Wechsel weiter. Für `deno.lock`-Dateien, die bereits Git-Merge-Konflikt-Marker aus einem verpatzten Rebase enthalten, löst Deno sie nun automatisch auf, vereinigt die additiven Sektionen und nimmt bei echten Spezifizierer-Konflikten die höhere Version ([#34726](https://github.com/denoland/deno/pull/34726)). Wenn ein `node_modules`-Verzeichnis in Gebrauch ist, installiert die neue opt-in-Einstellung `jsrDepsInNodeModules` `jsr:`-Abhängigkeiten über JSRs npm-Kompatibilitäts-Registry hinein ([#35029](https://github.com/denoland/deno/pull/35029)), analog dazu, wie pnpm und npm bereits JSR-Pakete behandeln.

Die neuen Subcommands der Abhängigkeitsverwaltung runden das Bild ab. `deno link` und `deno unlink` ([#34359](https://github.com/denoland/deno/pull/34359)) geben First-Class-CLI-Zugriff auf das `links`-Array in `deno.json` (den npm-Link-artigen Workflow für lokale JSR-Pakete). Das Feld `links` selbst ist in 2.9 stabil: Es wurde unter diesem Namen bereits in 2.3 ausgeliefert und war nie hinter einem Runtime-Flag verborgen, also lässt 2.9 einfach die verbliebene Unstable-Beschriftung fallen ([#34996](https://github.com/denoland/deno/pull/34996)). `deno list` ([#34972](https://github.com/denoland/deno/pull/34972)) druckt die Abhängigkeiten, die ein Projekt in `deno.json` und `package.json` deklariert, und löst ihre Versionen auf, das Äquivalent von `npm ls` / `pnpm list`. `deno watch` ([#35301](https://github.com/denoland/deno/pull/35301)) ist ein kurzer, besser auffindbarer Alias für `deno run --watch-hmr main.ts`, der bei Dateiänderungen mit Hot Module Replacement neu ausführt und neu startet, falls Hot Replacement fehlschlägt.

## deno fmt auf den lax-Engines

`deno fmt` wird auf den neuen lax-Formatierungs-Engines neu aufgebaut, die nur Whitespace verschieben: Sie ordnen nie um, requoten nie, lassen nie ein Token fallen und reichen fehlerhafte Eingaben durch statt zu erroren. HTML, XML und SVG werden nun von lax-markup formatiert, und sie werden standardmäßig ohne Flag formatiert ([#35174](https://github.com/denoland/deno/pull/35174)). Komponentenformate (Vue, Svelte, Astro, Vento, Nunjucks, Mustache) sind unter `--unstable-component` verfügbar. Ein 10-MB-Dokument, das vorher in 15 Minuten nicht formatiert werden konnte, braucht nun etwa eine Zehntelsekunde. CSS, SCSS und Less werden nun von lax-css formatiert (weiterhin unter `--unstable-css`), was eine lange Liste von Parse-Fehlern und Value-Mangling-Bugs fixt ([#35160](https://github.com/denoland/deno/pull/35160)). Beachten Sie, dass die eingerückte `.sass`-Syntax nicht mehr unterstützt wird. SQL-Formatierung (unter `--unstable-sql`) wird nun von lax-sql betrieben, das kanonische, dialektagnostische Ausgabe produziert ([#35161](https://github.com/denoland/deno/pull/35161)).

Zwei neue Konfigurationsoptionen für JavaScript und JSON: `sortNamedImports` und `sortNamedExports` steuern, wie benannte Spezifizierer geordnet werden (`caseInsensitive` (Standard), `caseSensitive`, `maintain` (Quellreihenfolge belassen, praktisch, um Biome's Sortierung zu matchen)) ([#33313](https://github.com/denoland/deno/pull/33313)); und `json.trailingCommas` steuert Trailing Commas in JSON und JSONC (`never`, `always`, `maintain`, `jsonc`) ([#33383](https://github.com/denoland/deno/pull/33383)). `deno fmt` liest nun `.editorconfig`-Dateien und nutzt sie, um alle Formatierungsoptionen zu füllen, die der Anwender nicht explizit gesetzt hat, mit einer Präzedenz CLI-Flags → deno.json → .editorconfig → eingebaute Defaults ([#34071](https://github.com/denoland/deno/pull/34071)).

## deno task, deno compile, deno bundle

Der Taskrunner nimmt Input-basierten Cache, Concurrency-Steuerung und mehrere neue Flags auf. Input-basierter Cache: Deklarieren Sie die Inputs einer Task mit `files` (und Outputs mit `output`), und Deno überspringt die Task vollständig, wenn nichts Relevantes sich geändert hat, und restauriert alle deklarierten Output-Artefakte direkt aus dem Cache ([#34509](https://github.com/denoland/deno/pull/34509)). Der Fingerabdruck enthält den Befehl, den Inhalt der durch `files` gematchten Dateien, die Werte aufgelisteter `env`-Variablen, die Fingerabdrücke der Abhängigkeiten der Task, das Host-OS, die CPU-Architektur und die Deno-Version. Argumente und env sind Teil des Schlüssels: `deno task build foo` und `deno task build bar` cachen unabhängig, und das Ändern eines gelisteten env-Werts invalidiert den Cache. Abhängigkeiten kaskadieren (eine Task läuft neu, wenn eine ihrer Abhängigkeiten neu lief, selbst wenn ihre eigenen Inputs unverändert sind). Sicher per Default: Wenn die Datei-Globs nichts matchen, wird die Task als nicht-cachebar behandelt und läuft immer; ein Tippfehler kann also nie einen falschen Cache-Hit erzeugen. npm-Skripte und Tasks ohne `command` werden nie gecacht.

Concurrency-Steuerung: `--jobs` (kurz `-j`, Alias `--concurrency`) begrenzt, wie viele Tasks in einem Workspace-Lauf gleichzeitig laufen; `--jobs 1` erzwingt sequenzielle Ausführung; es überschreibt die `DENO_JOBS`-Umgebungsvariable und defaulted auf die Anzahl verfügbarer CPUs ([#35318](https://github.com/denoland/deno/pull/35318)). Weitere Flags: `--if-present` beendet mit 0 statt zu erroren, wenn die benannte Task nicht existiert, passend zu npm ([#35315](https://github.com/denoland/deno/pull/35315)); `--env-file` lädt eine dotenv-Datei in die Task-Umgebung, ohne das Flag an jeden inneren Befehl weiterzureichen ([#34508](https://github.com/denoland/deno/pull/34508)); Ausschlussgruppen in Task-Namen-Wildcards (`deno task test:*(!e2e|interactive)`) führen jede `test:*`-Task außer den ausgeschlossenen aus ([#34506](https://github.com/denoland/deno/pull/34506)).

`deno compile` erhält `--include-as-is`, das eine Datei oder ein Verzeichnis in das virtuelle Dateisystem der Executable einbettet, ohne Modulauflösung oder Transpilation ([#32417](https://github.com/denoland/deno/pull/32417)). Wo `--include` Dateien durch den Modulgraph laufen lässt, ist `--include-as-is` für Assets und vorgefertigte Bundles gedacht, die Sie zur Laufzeit einfach per Filesystem-APIs verfügbar haben wollen. Die beiden Flags kombinieren, sodass Sie einige Module auflösen und andere verbatim in denselben Build einbetten können. Kompilierte Binaries erhalten auch echten persistenten Speicher: Ein Default-`Deno.openKv()`, `localStorage` und die caches-API persistieren nun in einem Per-App-Verzeichnis unter dem App-Data-Speicherort der Plattform statt auf In-Memory-Storage zurückzufallen ([#34618](https://github.com/denoland/deno/pull/34618)). Die Speicheridentität ist das neue Flag `--app-name`, das standardmäßig auf den Namen der Ausgabedatei fällt; zwei Binaries, die mit demselben `--app-name` gebaut wurden, teilen sich einen Store, und das Umbenennen einer Binary verliert nicht mehr deren Daten. Per Default embeddet `deno compile` den gesamten aufgelösten `node_modules`-Baum in die Binary; das neue experimentelle Flag `--bundle` lässt stattdessen den Entrypoint zunächst durch Deno's Bundler laufen (Tree-Shaking und Emission eines einzelnen Moduls), was Binaries für npm-schwere Projekte dramatisch schrumpfen kann (ein lodash-Hello-World fiel in Deno's eigenen Messungen von 11,6 MB auf 1,5 MB). Kombinieren Sie mit `--minify`, um das eingebettete Bundle weiter zu verkleinern ([#34527](https://github.com/denoland/deno/pull/34527), [#34532](https://github.com/denoland/deno/pull/34532), [#34536](https://github.com/denoland/deno/pull/34536)). `deno compile` nimmt auch einen `--watch`-Modus auf ([#34860](https://github.com/denoland/deno/pull/34860)). `deno bundle` kann nun mit `--declaration` ein gerolltes `.d.ts` neben dem gebundelten JavaScript ausgeben ([#33838](https://github.com/denoland/deno/pull/33838)) und versteht die Objektform von npms `package.json` `browser`-Feld beim Bundeln mit `--platform browser` ([#34407](https://github.com/denoland/deno/pull/34407)).

## Web-Platform- und Runtime-Ergänzungen

Sechs Ergänzungen der Web-Platform-Oberfläche erscheinen in 2.9. Die [Web Locks API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Locks_API) erscheint vollständig ([#31166](https://github.com/denoland/deno/pull/31166)) und erlaubt die Koordination des Zugriffs auf eine benannte Ressource über async Tasks und Worker hinweg durch `navigator.locks.request("config", async lock => { /* exklusiver Zugriff hier bis dieser Callback sich auflöst */ })`, mit Shared-vs-Exclusive-Modi, `ifAvailable`, `steal`, einem `AbortSignal` und `navigator.locks.query()` zur Inspektion gehaltener und ausstehender Locks. Happy Eyeballs v2 ([RFC 8305](https://www.rfc-editor.org/rfc/rfc8305)) landet in `Deno.connect` und `Deno.connectTls` ([#31726](https://github.com/denoland/deno/pull/31726)) und lässt IPv6- und IPv4-Adressen auf Dual-Stack-Netzwerken um die schnellere, zuverlässigere Verbindung konkurrieren, standardmäßig aktiv mit `autoSelectFamily: false` zum Abschalten. `navigator.userAgentData` erscheint in Window- und Worker-Scopes ([#34743](https://github.com/denoland/deno/pull/34743)). `RequestInit` akzeptiert das Fetch-Standard-`priority`-Member (`auto`, `high`, `low`) ([#34716](https://github.com/denoland/deno/pull/34716)). `Deno.watchFs` unterstützt eine `ignore`-Option für Pfade wie `.git` oder `build`-Output ([#31582](https://github.com/denoland/deno/pull/31582)). `process.kill` auf den eigenen Prozess verlangt kein `--allow-run` mehr ([#34382](https://github.com/denoland/deno/pull/34382)).

CSS-Modul-Importe erscheinen unter `--unstable-raw-imports` ([#35093](https://github.com/denoland/deno/pull/35093)), passend zum CSS module scripts Web-Standard: `import sheet from "./styles.css" with { type: "css" };` liefert eine `CSSStyleSheet`-Instanz, sodass derselbe Code in Deno und im Browser ohne Bundler-Schritt läuft. Stabiles `--unsafe-proto` ([#34738](https://github.com/denoland/deno/pull/34738), [#35192](https://github.com/denoland/deno/pull/35192)) ersetzt das unstable Flag, und wenn ein Programm nach Berührung des deaktivierten `Object.prototype.__proto__`-Accessors crasht, schlägt Deno vor, es damit neu zu starten. Der WebAssembly-ESM-Integration-Fix ([#34912](https://github.com/denoland/deno/pull/34912)) entpackt globale Exports aus importierten `.wasm`-Modulen, passend zur WebAssembly/ESM-Spec und Node. `Deno.serve` komprimiert Antwort-Bodies nicht mehr automatisch ([#35253](https://github.com/denoland/deno/pull/35253), [#35486](https://github.com/denoland/deno/pull/35486)); aktivieren Sie es pro Server mit `automaticCompression: true` oder prozessweit mit `DENO_SERVE_AUTOMATIC_COMPRESSION=1`. OpenTelemetry erhält `OTEL_TRACES_SAMPLER` (mit `OTEL_TRACES_SAMPLER_ARG`) für Head-Based Sampling, `OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT` und `OTEL_SPAN_EVENT_COUNT_LIMIT` für Per-Span-Caps und Auto-Instrumentation, die nun auch `node:http2`-Clients und -Server tracen ([#34764](https://github.com/denoland/deno/pull/34764), [#34787](https://github.com/denoland/deno/pull/34787), [#34795](https://github.com/denoland/deno/pull/34795), [#34510](https://github.com/denoland/deno/pull/34510)).

## Was dieses Release mit Deno's Trajektorie macht

Der 2.9-Zyklus ist das erste Mal, dass Deno drei ungefähr gleichwertige Schlagzeilenkategorien in einem einzigen getaggten Build ausliefert: einen großen Perf-Sprung (Cold Start, Speicher, Durchsatz), eine große Supply-Chain-Härtung (Minimum Release Age standardmäßig an, opt-in No-Downgrade Trust Policy) und eine große Feature-Lieferung für den Test-Runner (Snapshot-Tests, parametrisierte Tests, Sharding, Retries, Change-Aware-Auswahl, Coverage-Thresholds). Der Desktop-Subcommand, der [als PR #33441 am 16. Juni merged wurde](/articles/2026-06-16--deno-desktop-subcommand-wef-cef-browserwindow), erscheint endlich als erstes getaggtes Build; die Lockfile-Interop-Arbeit bedeutet, dass ein Node-Projekt mit wenigen Befehlen und bewahrtem Abhängigkeitsgraph zu Deno wechseln kann, und die WebCrypto-Modern-Algorithms-Arbeit bringt Deno auf dieselbe Post-Quantum-Kryptografie-Schiene wie Node 24 LTS und Node 26 Current.

Die Teile, die das Team als nächste Deno-Release-Kandidaten markiert hat, sind aus den PR-Beschreibungen ablesbar: Sharding vor dem Type-Check (der Trade-off der [#35057](https://github.com/denoland/deno/pull/35057)), Erweiterung der Web Locks API (Timeouts, `steal` mit Timeout), die No-Downgrade Trust Policy mit Per-Paket-Overrides jenseits des bestehenden `trust-policy-exclude[]`-Arrays, und `deno fmt`, das die lax-Engines von unstable zu stable befördert. Die vollständige Liste der 165+ PRs im 2.9-Zyklus steht auf [der Deno 2.9.0 GitHub-Release](https://github.com/denoland/deno/releases/tag/v2.9.0).