Hot Reload and Productivity Tips for .NET MAUI Development
Mobile development has always had a painful feedback loop: change code, build, deploy, navigate back to the screen you were working on, check the result. .NET MAUI's hot reload capabilities dramatically shorten this cycle — when they work properly. Here's how to get the most out of them.
XAML Hot Reload
XAML Hot Reload updates your UI in real-time as you save XAML files. No rebuild, no redeployment. It's enabled by default in Visual Studio and works with both emulators and physical devices.
What it handles:
- Adding, removing, and modifying UI elements
- Changing layout properties (margins, padding, sizes)
- Updating styles and resource dictionaries
- Modifying data templates
- Adding new event handlers (if the method already exists in code-behind)
What it doesn't handle:
- Adding new XAML files
- Changes to
x:Classdeclarations - Modifying generic styles in
App.xaml(sometimes) - Constructor logic in code-behind
Getting XAML Hot Reload Working Reliably
If hot reload is flaky — and it can be — check these settings in Visual Studio:
- Tools > Options > Debugging > Hot Reload — ensure ".NET MAUI XAML Hot Reload" is ticked
- Tools > Options > XAML Designer > XAML Hot Reload — ensure "Enable XAML Hot Reload" is on
- Target Debug configuration, not Release
If changes aren't appearing, try these in order:
- Save the file explicitly (Ctrl+S)
- Check the Hot Reload output window for errors
- Restart the debugging session
.NET Hot Reload
.NET Hot Reload applies C# code changes without restarting. It supports:
// You can modify method bodies
[RelayCommand]
private async Task LoadDataAsync()
{
// Change this logic and hot reload will pick it up
var items = await _service.GetItemsAsync();
Items = new ObservableCollection<Item>(items.OrderBy(i => i.Name));
}
Supported changes:
- Method body modifications
- Adding static methods and fields
- Adding lambda expressions
- Modifying lambda expressions
- Adding new classes (in some scenarios)
Unsupported changes:
- Modifying method signatures
- Adding or removing method parameters
- Changing base classes
- Adding new generic types
- Modifying struct layouts
When you hit an unsupported change, you'll see a warning in the output window. At that point, you need to stop and restart.
Practical Productivity Techniques
Use a Development Page
Create a scratch page for developing components in isolation:
// MauiProgram.cs — in Debug only
#if DEBUG
builder.Services.AddTransient<DevSandboxPage>();
Routing.RegisterRoute("dev", typeof(DevSandboxPage));
#endif
<!-- DevSandboxPage.xaml -->
<ContentPage Title="Dev Sandbox">
<ScrollView>
<VerticalStackLayout Padding="20" Spacing="10">
<!-- Drop whatever you're working on here -->
<local:CustomProgressBar Progress="0.7" />
<local:CustomProgressBar Progress="0.3" />
<local:CustomProgressBar Progress="1.0" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
This avoids navigating through your app to reach the screen you're iterating on.
Design-Time Data
Make your XAML previewer and hot reload sessions more productive by providing design-time data:
public class MainViewModel : ObservableObject
{
public MainViewModel()
{
}
// Design-time constructor
public MainViewModel(bool designMode)
{
Items = new ObservableCollection<Item>
{
new("Sample item 1"),
new("Sample item 2"),
new("Sample item 3"),
};
}
}
<ContentPage xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:BindingContext="{d:DesignInstance vm:MainViewModel,
IsDesignTimeCreatable=True}">
Target Windows for Fast Iteration
Android emulators are slow to deploy. During UI development, target Windows (WinUI) first — deployment is near-instant and hot reload is most reliable. Switch to Android/iOS only when you need to test platform-specific behaviour.
<TargetFrameworks>
net9.0-android;net9.0-ios;net9.0-maccatalyst;net9.0-windows10.0.19041.0
</TargetFrameworks>
Resource Dictionary Hot Reload
Centralise your colours and styles so you can tweak them with hot reload:
<!-- Resources/Styles/Colours.xaml -->
<ResourceDictionary>
<Color x:Key="Primary">#512BD4</Color>
<Color x:Key="Secondary">#DFD8F7</Color>
<Color x:Key="Accent">#2B0B98</Color>
</ResourceDictionary>
Changes to these values hot reload across your entire app. It's the fastest way to iterate on your colour scheme.
Conditional Compilation for Debugging
Add visual debugging aids that only appear in debug builds:
#if DEBUG
public static class DebugHelpers
{
public static void ShowLayoutBorders(Layout layout)
{
foreach (var child in layout.Children.OfType<View>())
{
child.Background = new SolidColorBrush(
new Color(
Random.Shared.NextSingle(),
Random.Shared.NextSingle(),
Random.Shared.NextSingle(),
0.2f));
}
}
}
#endif
Multi-Window Testing on Desktop
When targeting Windows or Mac Catalyst, test multiple windows simultaneously:
#if DEBUG && WINDOWS
// Open a second window showing a different page
var secondWindow = new Window(new NavigationPage(new SettingsPage()));
Application.Current.OpenWindow(secondWindow);
#endif
Build Performance
Speed up builds during development:
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<!-- Skip AOT during development -->
<RunAOTCompilation>false</RunAOTCompilation>
<!-- Faster Android builds -->
<AndroidLinkMode>None</AndroidLinkMode>
<EmbedAssembliesIntoApk>false</EmbedAssembliesIntoApk>
</PropertyGroup>
The feedback loop in MAUI development isn't as instant as web development with Vite or similar tools, but with proper use of hot reload, Windows-first iteration, and design-time data, you can get reasonably close. The key is knowing what hot reload can and can't handle, so you avoid unnecessary rebuild cycles.