On this page
Hot module replacement
deno desktop ships in Deno v2.9.0 and is not in a stable release yet. To try
it now, run deno upgrade canary to install the
canary build. The command, configuration
keys, and TypeScript APIs may still change before the feature is stable.
deno desktop --hmr .
--hmr enables hot module replacement during development. The mode is selected
automatically based on what your project looks like:
| Project type | HMR mechanism |
|---|---|
| Detected framework (Next.js etc.) | The framework's own dev server. |
Plain Deno.serve() script |
File watcher + Debugger.setScriptSource. |
In both modes the Deno runtime and the rendering backend (CEF, WebView, …) stay alive across changes. There is no full restart, no webview teardown, no reconnect.
Framework HMR Jump to heading
When framework detection identifies your project (see
Frameworks), --hmr runs the framework's own
dev server instead of its production server. The webview connects to that dev
server directly: fast refresh, state preservation, and error overlays all work
the same as in a browser tab.
deno desktop --hmr . # in a Next.js / Astro / Fresh / … project
The dev server's exact behavior comes from the framework. If next dev
preserves component state across edits in a browser, it preserves it in your
desktop app too. If astro dev shows an in-page error overlay on a syntax
error, you see the same overlay.
You do not need to run the framework's dev script separately;
deno desktop --hmr starts it as part of the desktop runtime.
Plain-app HMR Jump to heading
For projects without a detected framework, --hmr watches your source files and
uses V8's Debugger.setScriptSource to hot-swap modules into the running
isolate.
Deno.serve((req) => {
return new Response("hello world");
});
deno desktop --hmr main.ts
Edit main.ts (change the response body, add a route) and the change applies on
save. The runtime does not restart, the webview does not reload, the listening
socket stays bound.
What persists across reloads Jump to heading
Debugger.setScriptSource replaces the code of a function with new code.
Live values stay the same:
- Module-level state (top-level
let, top-levelMap, etc.) is preserved. - Open file handles, network connections, child processes: all preserved.
- The HTTP listener is preserved.
- Timers and intervals keep firing on their original schedule unless you
clearTimeout/clearIntervalthem.
What changes on the next call Jump to heading
The replaced functions execute their new bodies the next time they are called. So:
- A request handler change takes effect on the next request.
- A timer callback change takes effect on the next firing.
- An event listener change takes effect on the next event.
What HMR cannot do Jump to heading
Debugger.setScriptSource has limits. It cannot replace:
- Top-level statements that have already executed (a
console.logat module scope only runs when the module is first loaded). - The signature of a class, such as adding fields or changing constructors. The class declaration is replaced; existing instances keep their old shape.
- The set of imports. Adding a new
importline requires a full reload.
When the change is too disruptive to apply incrementally, --hmr falls back to
a full reload of the affected module. If even that is not safe (for example,
top-level state would be lost in a way the runtime cannot recover from), it logs
a warning suggesting a full restart.
Browser-side HMR Jump to heading
The webview is a browser. Browser HMR (fast refresh in React, Vue's HMR runtime,
etc.) runs entirely inside the rendering backend, talking to your dev server.
deno desktop --hmr does not interfere with it; if your framework wires browser
HMR up, it works as designed.
The Deno-side HMR described on this page is separate from browser HMR. The two coexist:
- A change to a React component file → browser HMR applies it inside the webview.
- A change to your
Deno.serve()handler or a binding implementation → Deno-side HMR applies it inside the runtime.
You almost never need to think about the split; both happen on save.
Limitations and caveats Jump to heading
--hmris for development only. Do not ship a binary built with--hmr; the file watcher and inspector overhead are not appropriate for end users.- Source maps are required for accurate line numbers in stack traces after a hot swap. They are emitted by default; do not disable them in your bundler config.
- HMR cooperates with
--inspect(see DevTools). You can attach a debugger to a running--hmrsession and step through newly-swapped code.