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:

What it doesn't handle:

Getting XAML Hot Reload Working Reliably

If hot reload is flaky — and it can be — check these settings in Visual Studio:

  1. Tools > Options > Debugging > Hot Reload — ensure ".NET MAUI XAML Hot Reload" is ticked
  2. Tools > Options > XAML Designer > XAML Hot Reload — ensure "Enable XAML Hot Reload" is on
  3. Target Debug configuration, not Release

If changes aren't appearing, try these in order:

.NET Hot Reload

.NET Hot Reload applies C# code changes without restarting. It supports:

Example.cs
// 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:

Unsupported changes:

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:

Example.cs
// MauiProgram.cs — in Debug only
#if DEBUG
builder.Services.AddTransient<DevSandboxPage>();
Routing.RegisterRoute("dev", typeof(DevSandboxPage));
#endif
config.xml
<!-- 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:

Example.cs
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"),
        };
    }
}
config.xml
<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.

MyApp.csproj
<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:

config.xml
<!-- 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:

Example.cs
#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:

Example.cs
#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:

MyApp.csproj
<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.