Visual Studio Hot Reload: Where It Works and Where It Stops
Hot Reload cuts restart cycles for .NET method changes, but structural edits still need a full rebuild. Know the boundaries to avoid wasted debug sessions.
15 Sept 2025, 14:00 UTC

The edit-compile-debug tax
You change a single line in a controller, hit save, and wait. The app restarts, the database reconnects, the authentication token refreshes, and you finally see the result. Multiply that by dozens of edits a day and the friction adds up. Visual Studio's Hot Reload promises to skip the restart for many changes, but it doesn't work everywhere. Knowing the boundary saves you from chasing a "why didn't it update?" rabbit hole.
How Hot Reload actually works
Hot Reload builds on the .NET runtime's Edit and Continue (EnC) APIs. When you save a supported file, the debugger sends the updated IL and metadata to the running process. The runtime pauses all managed threads at a safe point, swaps the method bodies atomically, and resumes execution. The app keeps its memory state — database connections, request context, UI state — intact.
This is distinct from the older "Edit and Continue" that only works at a breakpoint. Hot Reload applies changes while the application continues running, triggered by file save (Ctrl+S) or the Hot Reload button (Ctrl+Alt+F5).
Supported vs. unsupported edits
| Supported (no restart) | Unsupported (requires restart) |
|---|---|
| Method body changes (logic, expressions) | Adding/removing interfaces on a class |
| Adding/removing private methods | Changing generic type signatures |
| Modifying local variables, lambdas | Altering assembly references or NuGet packages |
| Razor (.cshtml/.razor) markup and CSS | Startup code: Program.cs, Startup.cs |
| Blazor component parameters and render logic | DI registration, middleware pipeline, entity model definitions |
Razor and CSS changes are handled by a separate ASP.NET Core middleware that recompiles components and pushes updates via WebSocket — independent of the .NET Hot Reload engine.
Worked example: controller action tweak
- Open Visual Studio 2022 17.8+ with the .NET 8 SDK installed.
- Create a new ASP.NET Core Web API project (template:
webapi). - Press F5 to start with debugging attached. The browser opens to the Swagger UI or the default
/weatherforecastendpoint. - In
WeatherForecastController.cs, change the summary string in theGet()method:// Before return Enumerable.Range(1, 5).Select(...); // After return Enumerable.Range(1, 5).Select(i => new WeatherForecast { Summary = "Hot Reload works!" }); - Press Ctrl+S to save. Within 1–3 seconds the browser reflects the new summary without a restart. The request pipeline, DI container, and any open database connections remain alive.
Where to run: Visual Studio 2022 17.8+ on Windows or Mac (VS for Mac supports Hot Reload for .NET 7+). Permissions: debugger must be attached (F5). Expected check: Output window → Hot Reload pane shows "Hot Reload applied changes to 1 of 1 projects". Risk: each apply incurs a brief global GC safe-point pause; avoid in latency-sensitive load tests.
Limitations that bite
- GC safe-point pause: all managed threads stop momentarily during the metadata swap. In high-throughput scenarios this can cause transient latency spikes.
- Source generators and analyzers: Hot Reload does not re-run source generators. If a generator emits code at compile time (e.g., minimal API endpoint mapping, DTOs), the generated output stays stale until a full rebuild.
- Docker and remote debugging: the debugger must attach to the container process, and source changes must propagate via volume mounts or dev tunnels. File watchers inside containers sometimes miss host-side saves.
- Blazor WebAssembly flicker: enabling "Hot Reload on File Save" (Tools → Options → Debugging → Hot Reload) can cause UI flicker if component state isn't designed for partial updates.
- Version gaps: .NET 6/7/8/9 each added support for edge cases (async iterators, ref structs). Check the Microsoft Learn supported scenarios page for your target framework.
Configure the behavior you want
By default, Hot Reload applies on save when the debugger is attached. Two toggles in Tools → Options → Debugging → Hot Reload control this:
- Enable Hot Reload — master switch (on by default).
- Hot Reload on File Save — applies changes automatically on Ctrl+S for ASP.NET Core projects. Turn this off if you prefer the explicit Ctrl+Alt+F5 button.
For containerized workloads, ensure docker-compose.yml mounts the source directory and the launch profile attaches the debugger ("Docker" or "Container" debug target).
Verify before you trust
When a change doesn't appear, open the Output window and select Hot Reload from the dropdown. You'll see either a success line or a specific error like "Hot Reload failed: adding interface implementation is not supported." That message is your signal to restart.
Quick test: add a new interface to a class, save, and watch the toast notification. It's the fastest way to internalize the boundary.
Bottom line
Hot Reload eliminates restarts for method-level logic, Razor markup, and CSS — the bulk of day-to-day tweaks. It stops at structural changes: DI setup, middleware, generic signatures, and anything that changes the assembly's shape. Keep the Output window's Hot Reload pane visible, and treat a "Hot Reload failed" toast as a documented restart requirement, not a bug.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.