Skip to main content
Hot reload lets you modify C# code while the game is running in the editor and have those changes take effect immediately. You can tweak component behaviour, fix bugs, and iterate on gameplay without breaking out of play mode.

How it works

s&box hot reload has two paths depending on what changed:
When only the bodies of existing methods or property accessors change — and no new types, fields, or members are added — the engine uses IL patching via the ILHotloadProcessor to swap in the new method implementations without reloading the full assembly.The source generator (Sandbox.Generator) analyses the syntax trees of your compilation. If it detects that only statement blocks have changed, it marks the affected methods with [MethodBodyChangeAttribute] or [PropertyAccessorBodyChangeAttribute] and annotates the assembly with [SupportsILHotloadAttribute]. The engine then patches only those method bodies in-place, leaving all existing object instances untouched.

Instance upgrading

The Hotload class (Sandbox.Hotload) manages the upgrade process. It tracks:
  • Watched assemblies — scanned for static fields holding instances of old types.
  • Watched instances — specific object roots to scan.
var hotload = new Hotload( addDefaultUpgraders: true );

// Watch static fields of an assembly
hotload.WatchAssembly<MyComponent>();

// Watch a specific object instance
hotload.WatchInstance( myObject );

// Register the swap
hotload.ReplacingAssembly( oldAssembly, newAssembly );

// Apply all queued swaps
hotload.UpdateReferences();
IInstanceUpgrader implementations handle the per-type upgrade logic (field migration, default-value injection for newly added fields, etc.). The default upgraders are registered automatically when you pass addDefaultUpgraders: true to the constructor.

What triggers a hot reload

The engine watches your project’s source files. When a .cs file is saved, the compiler is invoked in the background. If compilation succeeds, the hot reload pipeline runs automatically — you do not need to press any button.

Writing hot-reload-friendly components

Most components work with hot reload out of the box. A few patterns help ensure smooth upgrades:
using Sandbox;

public sealed class ScoreDisplay : Component
{
    // [Property] fields survive full reloads — the editor serializes
    // and restores their values automatically.
    [Property] public int Score { get; set; }
    [Property] public string PlayerName { get; set; } = "Player";

    protected override void OnUpdate()
    {
        // Method body changes use the fast IL path — no instance
        // disruption at all.
        Log.Info( $"{PlayerName}: {Score}" );
    }
}

Limitations

The following changes always trigger a full assembly reload and cannot use the IL fast path.
Change typeReason
Adding or removing a fieldChanges the object memory layout
Changing a field typeRequires value migration
Adding or removing a method signatureChanges the assembly’s public surface
Modifying a structStructs are value types; in-place patching is unsafe
Adding a new using directiveTreated as a declaration-level change by the analyser
Changing preprocessor symbolsChanges which code is compiled
Additionally, static fields are not automatically reset during a full reload. If you store mutable state in a static field, that state persists across hot reloads. This can cause unexpected behaviour if the new code assumes a clean initial state.
Prefer instance fields marked with [Property] for state that needs to survive or reset correctly across reloads. The editor serialises [Property] values and restores them after a reload.

Build docs developers (and LLMs) love