Watch and Hot Reload

This section documents MSBuild 18.9, the .NET SDK 10.0.402 (with its dotnet CLI) and NuGet 7.9, as published in the MSBuild, .NET and NuGet documentation on learn.microsoft.com, which is the reference these pages are written and verified against. Material about .NET 11 / NuGet 8.0 is still in preview and is always flagged as such — never presented as baseline.

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The C# Reference bibliography lists the reference material consulted while preparing these pages.

dotnet watch runs a command — dotnet run by default, or test, build and others named after it — and runs it again whenever a watched file changes. With hot reload, many code edits are applied to the running process instead, so the application keeps its state. This page exercises both with .NET SDK 10.0.402 on a small console program.

A hot reload and a rude edit

The program prints a counter every second:

for (var i = 0; ; i++)
{
    Console.WriteLine(Message(i));
    Thread.Sleep(1000);
}

static string Message(int i) => $"tick {i}";

dotnet watch --non-interactive was started, and after a few seconds two edits were made: first the message text, then the parameter type of Message (int to long). The watcher’s output, without the program’s own lines:

dotnet watch ๐Ÿ”ฅ Hot reload enabled. For a list of supported edits, see https://aka.ms/dotnet/hot-reload.
dotnet watch ๐Ÿ’ก Press Ctrl+R to restart.
  W -> ~/watch/bin/Debug/net10.0/W.dll

Build succeeded.
dotnet watch โŒš Loading projects ...
dotnet watch โŒš Loaded 1 project(s) in 0.4s.
dotnet watch โŒš Waiting for changes
dotnet watch โŒš File updated: ./Program.cs
dotnet watch ๐Ÿ”ฅ C# and Razor changes applied in 1204ms.
dotnet watch โŒš File updated: ./Program.cs
dotnet watch ๐Ÿ”ฅ Restart is needed to apply the changes.
dotnet watch โŒš [W (net10.0)] Exited
  W -> ~/watch/bin/Debug/net10.0/W.dll

Build succeeded.
dotnet watch โŒš Waiting for changes

And the program’s output around the two edits:

tick 9
tick 10
balance check 11
balance check 12
โ€ฆ
balance check 17
balance check 0
balance check 1
  • The first edit was hot-reloaded. The new text appeared at 11: the loop and its counter kept running, and only the method body was replaced.

  • The second edit was a rude edit. Changing a method signature cannot be applied to running code, so the process was stopped, rebuilt and started again — the counter restarted at 0. In an interactive terminal dotnet watch asks first: "Do you want to restart your app - Yes (y) / No (n) / Always (a) / Never (v)?"; --non-interactive restarts without asking.

Which edits hot reload supports depends on the runtime and the project type (adding methods and fields, changing method bodies and lambdas are supported; changing signatures, base types or generic type definitions generally are not). --no-hot-reload turns it off and restores the plain re-run behaviour; Ctrl+R restarts on demand.

What is watched

dotnet watch watches the Watch item group, which by default holds all Compile and EmbeddedResource items (**/*.cs, the project file, **/*.resx, plus wwwroot/** in web projects), across the whole graph of project references. --list prints it without starting anything:

dotnet watch --list
~/watch/Program.cs
~/watch/W.csproj

A data file read by the program is not in the list. Adding it — and opting a file in or out explicitly — is done with items:

<ItemGroup>
  <Watch Include="accounts.txt" />
  <Compile Update="Program.cs" Watch="true" />
</ItemGroup>
~/watch/accounts.txt
~/watch/Program.cs
~/watch/W.csproj

Watch="false" on a Compile, EmbeddedResource or ProjectReference item excludes it, and from .NET 10 the DefaultItemExcludes property excludes whole folders or patterns ($(DefaultItemExcludes);**/App_Data/**;**/*.log).

A log file that wakes the watcher

The first run of the experiment above redirected the watcher’s output to watch.log inside the project folder. Every write to the log was reported as a change:

dotnet watch โŒš File updated: ./watch.log
dotnet watch โŒš No managed code changes to apply.
dotnet watch โŒš File updated: ./watch.log
dotnet watch โŒš No managed code changes to apply.

 — repeated for every line the program printed, although --list does not show watch.log. Nothing was rebuilt, but the output was flooded. Keep logs, databases and other files the application writes outside the project folder, or exclude them with DefaultItemExcludes.

Other commands

dotnet watch test re-runs the tests on every change, and dotnet watch build only rebuilds — both without hot reload. dotnet watch --file app.cs (or dotnet watch app.cs) watches a file-based app (Run and File-Based Apps).

Common mistakes

  • Expecting a rude edit to apply — the app restarts and loses its state.

  • Writing files into the project folder at run time — the watcher reacts to every write.

  • Data files that should trigger a restart but are not Watch items — add them.

  • Using dotnet watch in CI — it never exits; it is an inner-loop tool.