How do I do hmr in rust

Hi guys I'm new to rust. I have experience with js/ts .

While reading the cargo book I saw that there is no built-in command for dev/watch.
Is there any alternative for it ??
what's the most popular solution for it in rust ecosystem??
And normally in js ecosystem I got that out of the box like bun,node,deno all have something similar out of the box.

So is there any issue there??

Do you mean something like this: Overview - Bacon ? I am not sure if i understood what you mean, but i've used bacon and it's good.

If you’re looking for modifying the code of a running program, check out subsecond.

However, this technique is very fragile. It’s fundamentally hard to make arbitrary changes to a running program that has been compiled to machine code and isn’t part of a “virtual machine”/“dynamic language” setup like JavaScript. The price of the run-time performance benefits is less run-time flexibility.

ok, so what is the normal procedure for tasks that require it like when working on a gui application in that case with out any hmr wont that mean ill need to recompile on every change??


also what about live reloading like if i work on a backend project typically in other tools it auto reloads (compile/ restart the server) when i make change on any files to test it quickly . almost all major ecosystem has some tool for that which one is most widely used in rust ?

like i update a API endpoints logic and it will with recompile and restart the sever so i don't need to run cargo run every time i change something.
basically its nodemon (node js), air (go lang) these type of tool for rust.

The crate that @increasing mentioned in their reply is what you're looking for.

I wouldn’t say so – bacon is a nice tool but it’s for convenient recompilation when you change source files, it has nothing to do with any “Hot Module Replacement” (HMR) that OP seems to be asking about.

Edit: I mean I guess it relates to the ask of “don't need to run cargo run every time i change something”.

True. It's not hot module replacement, but for all intents and purposes it seems to be what the OP is looking for.

bacon has a .toml file - if you edit the [jobs.run] section I think you can get it to re-launch your server.

Hot module reloading is tricky in most languages; Javascript is one of a lucky few that has good tools for it. The "standard" practice for native GUI apps is to use a WYSIWYG/RAD GUI editor (XCode, Visual Studio, QT creator, Glade, Lazarus, Gorm, etc.). In some ways this is even faster than hot reload because your changes take effect instantaneously.

If your GUI toolkit doesn't have something like this or you want the other benefits of code hot reloading, then it's still possible:

This tutorial is in C++ but the technique works in Rust as well. The main idea is that you structure most of your application code as a shared library and store your application's state outside of it (similar to how React fast-refresh works, if you're familiar with that).

For me, having cargo clippy run every time I save a file is good enough… but then again, I imagine the code I work on is relatively low level (such that I benefit a lot from Rust’s type system, and the code does not have very complicated high-level logic or purely logical interactions between different parts of the code, which cargo clippy has a much lower chance of catching).

I do recall that tools like trunk can automatically recompile the backend code of a server. (Maybe the frontend too?) I assume most tools for doing web dev stuff in Rust have a similar utility.

That’s all to say, many Rust projects don’t need hot module reloading. It’s instead provided by tools specific to GUI development.

If your app is web, then CGI works in the way. Every CGI request pulls a fresh copy of your Rust program. It works like a magic. My editor has option - compile on save on. It it can't be compiled for some reason, then old copy still works. Development happens magically fast and transparent, like Java or JavaScript.

Not sure about your understanding level of Compiled vs Interpreted languages are, but if you want a simple reason why you can't achieve exactly the same as HMR that react offers is that JS / TS are interpreted languages, which basically means that the "hot" bit of the HMR is possible since u can just pass the new code to the interpreter. However, since rust compiles, the closest thing you can achieve is recompilation, which is effective Hot module reloading without the hot bit which is what bacon offers (recompilation on code change)

Interpreted vs compiled doesn't actually have much to do with whether HMR is possible, I don't think. The important thing is whether parts of the program can be parsed/compiled independently and swapped out at runtime (which is possible in all mainstream languages and OSs as far as I'm aware). Good HMR support is primarily a tooling issue.

I wrote up a quick minimal (laggy, leaky, Linux-only) rust HMR example using EGui:

If you do cargo r and then edit src/lib.rs your changes will show up in the application without needing to restart it.

Yep, trunk rebuilds ones front end Rust into WASM and signals the web browser to reload it.

It's awesome, man. You are genius. I asked for such tool for ages, but now it's in my pocket.

I see HMR and JS build tools. I understand that you're talking about hot-reloading your code to see changes in real time. I will take a moment to explain my thoughts on this.

If you take a little time to think about it, this is a really complicated problem.
Rust compiles to a native binary without a built-in runtime that manages modules or supports swapping code at runtime. While debug info exists, it’s not designed for safely swapping parts of a running program.

Not only that, changes in traits, function signatures or type definitions can significantly affect the generated machine code. This would have to immediately retrigger any static analysis as well as the recompilation of large parts of the crate and its dependents.

Compilation is also quite heavy, due to the amounts of static analysis required to make Rust as useful as it is. Also LLVM. This means that the naive approach of just recompiling the entire program on changes (even with incremental compilation enabled) may yield underwhelming results.

Note

If you would like to try that approach anyway (since it isn't particularly intrusive), check out cargo-watch. This can be used to recompile and rerun a binary on source changes.

Unfortunately, as a side effect it will also reset program state on reruns (obviously).


JavaScript and similar languages approach this differently. They run inside a long-lived runtime (like a browser or Node.js) that manages code as modules at runtime. This makes it possible to reload individual modules while the program is still running, often preserving application state. Because execution happens within this managed environment rather than as a standalone native binary, tooling can hook into the module system and swap code more easily.

The type systems are generally less strict and less coupled to code generation. Changes to source code don’t necessarily affect the program outside of nearby scope.

These languages are also built in a way that makes them compile very quickly. There isn't as much analysis involved in compilation, since a lot of the work is offloaded to runtime. What counts as a compilation unit is different as well, though here it depends on the tooling you use. Overall this means that small changes result in smaller units of work.

It is fairly easy to make a JS runtime hold additional information across reloads, since there is a long-lived runtime that can preserve state while you reload a single module. (Again, JS modules are a runtime concept, with enough information attached to them that it is relatively straightforward to swap out the code.) The persistent data allows you to come back to a previous state after reloading a module. This way you don't have to go through five menus just to get back to the button you're styling every time you change the color.

Rust doesn’t provide this kind of runtime or module system out of the box. Both languages serve different purposes and run in different environments. Rust supports use cases like embedded development, where resources are scarce and precise optimization as well as runtime predictability are crucial, while it is rather unlikely you would run into a JS powered car. At least I hope that future isn't coming.

I hope this gives you a clear picture of the kinds of problems such tooling has to overcome for it to be useful in this scenario. This may be helpful in choosing the right approach for your project.

Solutions you could consider:

  • Using Tauri, which allows you to develop your Rust application with a web-stack based frontend. This way you can use bun, node, deno etc. for the GUI part. There are some drawbacks though (primarily having to deal with IPC). I imagine this would be the most realistic solution for you.
  • Using subsecond as @kpreid mentioned. This allows you to keep everything in Rust, but it's an experimental solution that swaps out chunks of machine code at runtime. I wouldn't say its production ready, but it is a development tool, so if you're willing to adapt your code and workflow to it, it could help.
  • You could implement something lighter on your own, for example run a QuickJS runtime inside your app and implement the GUI part there. Though that would involve a lot of setup on your part. You could also do the same with WebAssembly if you were to keep the frontend in Rust, but mind the compilation speed.

The runtime that Rust needs for HMR support is provided by the the operating system, which does indeed manage modules and support swapping code at runtime. Javascript as used in practice is AOT-compiled (and statically typed!) and requires recompilation whenever a source file is edited. The critical difference between the two languages is that JS tooling treats HMR as a first-class use case while Rust tooling does not.

Very few languages have good HMR support and the ones that do are GUI-focused. For historical reasons these will naturally tend towards being more dynamic/object-oriented.

What you're saying is technically correct and you make good points, while maybe being a bit pedantic. I admit I did oversimplify, since I was trying to answer the OP's question in a useful manner. Yes, I do understand that V8 and the like are closer to the situation here in some regards. Yes, I know we have dynamic libraries. I do not think that makes implementing HMR in Rust as trivial as you're implying it to be.

I'm not entirely sure this is the best place to discuss whether Rust should have native (or similar) support for HMR, although I do think a conversation like this on the Internals forum could be interesting. There are questions to asked about whether this would actually be useful at scale considering how much effort designing a language-native system realistically would be, vs, for example, letting the ecosystem come up with solutions and allow them to evolve slowly. Again, subsecond has been mentioned already.

I said nothing to imply that implementing HMR in Rust is trivial. It's not trivial in Javascript, either. Your post went to great lengths to explain that Rust's nativeness/type-system/optimizations are the reason it has bad HMR support; my contradicting that isn't being "pedantic."

When I say Javascript is AoT compiled in practice, I'm not referring to V8, I'm referring to the tools JS developers use to create the javascript code bundle (webpack/babel/tsc/vite/esbuild/etc.). These tools do basically the same thing that rustc does.