Hot reload is one of s&box’s most important developer features. When you save a C# file, the engine recompiles your code, swaps the old assembly for the new one at runtime, migrates existing object state to the new types, and continues running — all without stopping or restarting the game. This page explains how the system works, how to useDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/facepunch/sbox-public/llms.txt
Use this file to discover all available pages before exploring further.
IHotloadManaged to respond to reload events, and what the system cannot handle.
How hot reload works
The s&box hot-reload system is implemented inSandbox.Hotload and works at the .NET assembly level:
Detect a change
The editor watches your project’s source files. When a
.cs file is saved, a recompile is triggered using the incremental compiler in Sandbox.Compiling.Build the new assembly
The compiler produces a new version of your game assembly. If compilation fails, the running assembly is unchanged and errors are reported in the editor console.
Register the assembly swap
The new assembly is registered alongside the old one using
Hotload.ReplacingAssembly(oldAssembly, newAssembly). Both assemblies are tracked until UpdateReferences is called.Migrate live instances
The hotload system walks all live objects reachable from static fields and watched roots. For each instance whose type has changed, it creates a new instance of the updated type, copies field values across (including newly-added fields set to their defaults), and replaces all references to the old instance with the new one.
IHotloadManaged
For types that need to save or restore custom state across a reload, implement theIHotloadManaged interface. The engine calls its methods during the upgrade pass.
All four
IHotloadManaged methods have default implementations and are optional to override. Implement only the ones you need.When to use IHotloadManaged
- Caches keyed by type — type identity changes after a reload, so caches must be invalidated. The engine’s own
ReflectionCache<TKey, TValue>usesPersisted()for this. - Unmanaged resources — if your object holds a native handle, implement
Failed()to dispose it when the upgrade fails. - Registered state — if your system maintains a registry (e.g. a list of active listeners), use
Destroyed/Createdto transfer the list to the new instance.
SkipHotload
Apply[SkipHotload] to a class, struct, field, or property to tell the upgrade pass to skip it. The engine will not attempt to migrate the annotated member during a reload.
SB3000 will warn you about).
Limitations
Not everything can be hot-reloaded. The following changes require a full editor restart or project reload:New base types
Adding or removing a base class from a type changes its identity in ways the upgrade pass cannot handle.
Added generic parameters
Changing a type from
Foo to Foo<T> changes its name mangling and cannot be migrated.Removed assemblies
Removing a project or assembly reference from the build requires a full reload.
Engine/framework code
Changes to the engine itself (
Sandbox.Engine, Sandbox.System, etc.) are not hot-reloaded; they require a full editor restart.Assembly ignorelist
Assemblies can be explicitly excluded from the upgrade pass by callingHotload.IgnoreAssembly. Any fields declared on types in an ignored assembly are skipped during reference updates. The engine does this automatically for Sandbox.Hotload.dll itself and Mono.Cecil.dll.
Practical tips
- Keep component state in
[Property]-decorated properties — the serializer preserves them across reloads because they are also written to the scene file. - Avoid caching
System.Typereferences in static fields across hot-reload boundaries. Use[SkipHotload]on such caches and repopulate them lazily. - If a component stops behaving correctly after a reload, use Recompile All in the editor to force a clean assembly build.
Scripting basics
Component lifecycle, properties, and attributes.
Component API reference
Full API reference for the Component base class.