Open-source project
Kira-NT/HotAvalonia avatar
Kira-NT/HotAvalonia

HotAvalonia gives Avalonia a hot reload that does not need a particular IDE

🔥 Supercharge your Avalonia development experience with hot reload capabilities

534 stars19 forksC#MIT

At a glance

What is it?
HotAvalonia is an IDE-agnostic hot reload plugin for Avalonia that applies XAML edits to a running application in real time. Its most useful feature is the one it does not have: it works the same way from Rider, from Visual Studio and from the command line, and it is configured entirely through MSBuild properties rather than through an IDE extension.
Who is it for?
Adopt HotAvalonia if you build Avalonia user interfaces and edit XAML, because the reload cycle goes from seconds to immediate and it works whichever editor you use. Skip it if you only touch view models, since the plugin is about XAML, and if you ship the same binary to production without thinking about it, because the default enabling is tied to the Debug configuration.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 42 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

IDE-agnostic on purpose

HotAvalonia is an IDE-agnostic hot reload plugin for Avalonia that lets you see UI changes in real time as you edit XAML files, and the first claim in that sentence is the one that sets it apart.

Avalonia is a cross-platform UI framework, and its tooling story has always been the awkward part of using it from a non-Microsoft environment. The hot reload stories that came before it were typically tied to a specific IDE, which meant the plugin worked for the people using that IDE and not for everybody else.

This one is not. It works on Linux, macOS, Windows and Android, and the mechanism is that it hooks into the running application rather than into the editor. The consequence is that your editor can be Rider, Visual Studio, or anything else that can write a file and start a debugger.

The framing in the description is that it drastically accelerates your design and development workflow. That is the standard claim for a hot reload tool, and it is true, but the reason matters more than the effect: XAML is a declarative markup language where you describe a layout, so you change the markup and you want to see what it means. Without hot reload, that loop is edit, build, run, look, and the build is the expensive part. With it, the loop is edit, look.

The project is C#, MIT licensed, with the default branch main and releases v3.1.5 from 2026-09-11, v3.1.4 from 2026-07-18 and v3.1.3 from 2026-06-27. The last push was on 2026-09-11, which is the same day as the latest release.

The repository layout is conventional for a .NET tool with samples. There is src/, samples/ with a HotReloadDemo, a Desktop variant and an Android variant, a Directory.Build.props and Directory.Build.targets, a global.json, an .editorconfig and a .vscode directory.

The .slnx extension on the solution file is worth noticing. That is the newer XML-based solution format, and its presence tells you the project has been kept on current tooling rather than pinned to the old format.

Installation, and the one rule about projects

The installation is two package references in your project file, which can be a .csproj, an .fsproj or a .vbproj.

xml
<!-- Don't forget to replace $(AvaloniaVersion) with the actual Avalonia package version. -->
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="$(AvaloniaVersion)" PrivateAssets="All" Publish="True" />
<PackageReference Include="HotAvalonia" Version="3.*" PrivateAssets="All" Publish="True" />

That is genuinely the whole setup. You start debugging your app as you normally would, make changes to some XAML files, and see them applied in real time.

The two attributes on the HotAvalonia reference are what make it safe to ship. PrivateAssets means the reference is not exposed to projects that depend on yours, and Publish means the package is not included in the published output. The documentation then states it plainly: HotAvalonia is a development-only dependency, meaning it doesn't affect your Release builds in any way, shape, or form, and its binaries are not shipped with your application.

That property is the thing to insist on in a tool like this. A hot reload plugin that ends up in your published output is a plugin that carries a file watcher and a reload mechanism into production, and the version of the plugin that matches your Avalonia version becomes a thing that can break your published application.

The rule about multi-project setups is the one practical detail to get right. HotAvalonia must be installed into your startup project, the one that produces the final executable, and it is also highly recommended to install it in every project that contains Avalonia controls to ensure the most stable hot reload experience possible.

The reasoning is fairly straightforward. The startup project is where the running application lives and where the reload event has to be handled, so the reference has to be there. The recommendation about every project with Avalonia controls is about the controls themselves: if a control lives in a separate assembly, the reloader has to be able to find and rebuild it, and having the plugin present in that assembly makes that possible.

Getting this wrong is the most likely reason someone installs the plugin and sees nothing happen.

Two optional dependencies, and what each one is for

There are two optional dependencies, and each one exists because of a specific limitation.

The first is Avalonia.Markup.Xaml.Loader, the official Avalonia package responsible for runtime XAML parsing. The reason HotAvalonia depends on it at all is compatibility: to accommodate users of all Avalonia releases starting from v11.0.0, HotAvalonia ships with a pretty old version of this library.

That is an honest admission of a compromise. The library has to work with every Avalonia release from 11.0.0 onwards, so it pins the oldest version that satisfies all of them, and the cost is that on a current Avalonia release you are running an old parser. The documentation says this can cause issues if you are experimenting with nightly builds of the next major Avalonia release, in which case you may need to manually bump the dependency:

xml
    <PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="$(AvaloniaVersion)" PrivateAssets="All" />

That is a good example of the right way to handle a version-compatibility problem. Rather than refusing to work with old versions or pretending the problem does not exist, the project pins to a known-good version, says so, and tells you how to opt out of the pin when you are on something newer.

The second optional dependency is MonoMod.RuntimeDetour, and the reason is more interesting. If you want to hot reload embedded assets such as icons and images, HotAvalonia needs a way to perform method injections into optimized code, and that is what this library is for. Without it, hot reload support is limited to XAML files only.

So the two tiers are clear. XAML hot reload works out of the box. Reloading embedded resources needs runtime method injection, which needs a library that can detour methods at runtime, which has consequences for how the code is compiled and for which platforms it works.

As with the main package, in a multi-project setup these packages only need to be referenced from the startup project.

The MSBuild properties, and why the defaults are conditional

The configuration surface is MSBuild properties in the project file, and the documentation says plainly that many of the features can be adjusted this way. The list is described as non-exhaustive.

xml
<PropertyGroup>
  <!-- Specifies whether HotAvalonia is enabled.                                          -->
  <!-- Please, do not enable it unconditionally.                                          -->
  <!--                                                                                    -->
  <!-- Default: true if the current configuration is Debug; otherwise, false.             -->
  <!-- Options: true, false, enable, disable                                              -->
  <HotAvalonia>$(IsDebug)</HotAvalonia>

  <!-- Specifies how aggressively HotAvalonia reloads your app when it detects an update. -->
  <!--                                                                                    -->
  <!-- - Minimal:    Only the affected control is reloaded.                               -->
  <!--                                                                                    -->
  <!-- - Balanced:   HotAvalonia attempts to identify controls that depend on the updated -->
  <!--               instance and reloads them as well.                                   -->
  <!--                                                                                    -->
  <!-- - Aggressive: The entire app is reloaded on every change.                          -->
  <!--                                                                                    -->
  <!-- Default: Balanced                                                                  -->
  <!-- Options: Minimal, Balanced, Aggressive                                             -->
  <HotAvaloniaMode>Balanced</HotAvaloniaMode>

  <!-- Defines a hotkey used to trigger an app-wide hot reload event.                     -->
  <!--                                                                                    -->
  <!-- Default: Alt+F5                                                                    -->
  <!-- Options: F11, Ctrl+R, Ctrl+Shift+H, disable, ...                                   -->
  <HotAvaloniaHotkey>Alt+F5</HotAvaloniaHotkey>

  <!-- Specifies the default timeout, in milliseconds, for hot reload-related operations. -->
  <!--                                                                                    -->
  <!-- Default: 10000                                                                     -->
  <!-- Options: 30000, 5000, 1000, 0, disable, ...                                        -->
  <HotAvaloniaTimeout>10000</HotAvaloniaTimeout>

  <!-- Specifies whether hot reload should be enabled automatically or if the user should -->
  <!-- manually call .UseHotReload() on their AppBuilder instance.                        -->
  <!--                                                                                    -->
  <!-- Default: true if the current project is a startup project; otherwise, false.       -->
  <!-- Options: true, false, enable, disable                                              -->
  <HotAvaloniaAutoEnable>$(IsExe)</HotAvaloniaAutoEnable>

  <!-- Specifies whether HotAvalonia should connect to a remote file system instead of    -->
  <!-- querying the local one.                                                            -->
  <!--                                                                                    -->
  <!-- Default: true for Android, iOS, and browser builds; otherwise, false.              -->
  <!-- Options: true, false, enable, disable                                              -->
  <HotAvaloniaRemote>$(IsNotDesktop)</HotAvaloniaRemote>

The properties are grouped into four settings, each with an inline comment that states the default and the options, which makes the project file itself the documentation.

The first property is whether HotAvalonia is enabled at all, with the value defaulting to $(IsDebug). That is a conditional default: it turns itself on in a Debug configuration and off otherwise, with no need to remember to disable it before shipping. The comment warns not to enable it unconditionally, which is the same concern as the Publish attribute.

The second is how aggressively the app reloads, with three modes. Minimal reloads only the affected control. Balanced attempts to identify controls that depend on the updated instance and reloads them as well, and that is the default. Aggressive reloads the entire app on every change.

The Balanced default is the interesting choice. The dependency problem in a UI tree is real: a control bound to a property that a changed control also depends on has to be updated, and if the reloader cannot work that out then the stale state stays. Aggressive mode guarantees correctness at the cost of losing the window state and reloading the whole UI, and Minimal mode is fast but can leave the app in a state that does not match what you will see on a fresh launch. Balanced is the pragmatic middle, and it is the one that gets the most use because it does not require you to think about which mode you are in.

The third property is the hotkey that triggers an app-wide hot reload, defaulting to Alt+F5, with F11, Ctrl+R, Ctrl+Shift+H and disable among the options. Having a manual trigger alongside the automatic file watching is what makes the tool usable when the automatic detection misses a change.

The fourth is the timeout for hot reload related operations, defaulting to ten thousand milliseconds, with a shorter value useful for a fast inner loop.

Then there are two more beyond the block shown. One specifies whether hot reload should be enabled automatically or whether the user should manually call UseHotReload() on their AppBuilder instance, defaulting to true if the current project is a startup project and false otherwise. The other specifies whether HotAvalonia should connect to a remote file system instead of querying the local one, defaulting to true for Android, iOS and browser builds and false otherwise.

The remote file system property, and what it implies

The HotAvaloniaRemote property is the one that deserves a second look, because it points at a case that is easy to miss.

The property specifies whether HotAvalonia should connect to a remote file system instead of querying the local one, and its default is true for Android, iOS and browser builds and false otherwise.

The reason is platform structure rather than preference. On a desktop build, the application and the source files are on the same machine, so the reloader can watch the local file system directly. On Android, iOS and browser builds, the code is not running on the machine where your files are, or at least not in a way where a local watch is meaningful, so the reloader has to reach out to a file system service running on the development machine instead.

That is why the property is expressed in terms of a build property, $(IsNotDesktop). The plugin infers the right default from the target platform rather than asking you to remember to set it.

The design of the defaults across all the properties follows the same pattern. The enabled flag follows the Debug configuration. The auto-enable flag follows whether the project is a startup project. The remote flag follows the target platform. Each one has a sensible default that is correct in the common case and a comment telling you what to do when it is not.

There is a broader point here about how MSBuild properties are a good configuration mechanism for a development tool. They live in the project file, so they are versioned, so a team shares them, and so a setting cannot be lost on one machine and kept on another. The alternative, a configuration dialog or an environment variable, tends to drift between developers.

The exception is the properties that are machine-specific, and those are handled by the repository layout instead. There is a local.defaults.properties style pattern in comparable projects, and in this repository the Directory.Build.props and Directory.Build.targets files are where shared build configuration lives, with samples/Directory.Build.targets showing how the samples override it.

Where this fits against the alternatives

The comparison is with the other ways to shorten the Avalonia development loop.

The first is to use the XAML previewer. Avalonia has one, and it shows you a rendered view of a control without running the application. The limitation is obvious once you use it: a preview renders one control in isolation, with no surrounding layout, no data binding and no application state. It answers a narrow question well and cannot answer the question you usually have, which is what happens in the running application.

The second is to run the application under the .NET hot reload mechanism, which re-applies method body changes to a running process. That works for C# code and it does not work for XAML, because XAML is not compiled into method bodies the way the runtime understands them. For a UI framework where the markup is the thing you change most, that is a large gap.

The third is to rebuild and restart, which is what everybody does without one of these tools. On a modern machine that is a few seconds for a small project, and it is the number that multiplies by the number of times you change a layout.

HotAvalonia's answer is the narrowest of the three, and that is its value. It does one thing, it does it at the layer where the framework can do it, and it is configured entirely through the build file so it is reproducible across a team.

The limitation to weigh is the one the optional dependencies reveal. Runtime XAML parsing has to happen for the reload to work, and HotAvalonia's approach to that involves runtime method injection for the embedded asset case. Method injection into optimised code is a technique with sharp edges, and the fact that it is optional rather than required tells you the author has thought about where it is safe to draw the line.

The practical advice is to start with the two package references and nothing else. The default configuration gives you XAML hot reload, which is the case that covers most of the work. If you find yourself needing to change an embedded icon and reloading it, add the detour dependency then, rather than carrying it from the start.

Editorial conclusion

Adopt HotAvalonia if you build Avalonia user interfaces and edit XAML, because the reload cycle goes from seconds to immediate and it works whichever editor you use. Skip it if you only touch view models, since the plugin is about XAML, and if you ship the same binary to production without thinking about it, because the default enabling is tied to the Debug configuration. Verify first where the package reference goes in a multi-project solution, that your Avalonia version is one the loader dependency supports, and whether you need the runtime detour package for embedded assets.

Frequently asked questions

What is HotAvalonia and how do I install it?

It is an IDE-agnostic hot reload plugin for Avalonia that applies XAML changes to a running application in real time, supporting Linux, macOS, Windows and Android. You add two package references to your project file, which can be a .csproj, an .fsproj or a .vbproj: Avalonia.Markup.Xaml.Loader and HotAvalonia itself at version 3.*, both with PrivateAssets and Publish set. In a multi-project setup the reference must go into the startup project, and it is recommended in every project that contains Avalonia controls.

What are HotAvalonia's optional dependencies for?

Avalonia.Markup.Xaml.Loader is the official package for runtime XAML parsing, and HotAvalonia ships with a pretty old version of it so that it supports every Avalonia release from v11.0.0 onwards, which can cause issues on nightly builds and may need a manual version bump. MonoMod.RuntimeDetour is needed to hot reload embedded assets such as icons and images, because that requires method injections into optimized code; without it, hot reload support is limited to XAML files only.

How do I configure the HotAvalonia reload behaviour?

Through MSBuild properties in the project file. HotAvalonia controls whether the plugin is enabled, defaulting to the IsDebug value so it turns off outside a Debug build. HotAvaloniaMode sets the reload aggressiveness to Minimal, Balanced or Aggressive, with Balanced as the default. HotAvaloniaHotkey sets the app-wide reload hotkey, defaulting to Alt+F5, and HotAvaloniaTimeout sets the timeout in milliseconds, defaulting to 10000.

Official sources

  1. Issues
  2. Kira-NT/HotAvalonia on GitHub
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/kira-nt-hotavalonia.svg)](https://hysenlabs.com/projects/kira-nt-hotavalonia)

Was this useful?