Enter Play mode without domain reload
Understand how entering Play mode without domain reload affects your application state and how you can compensate for these effects in your code.
Read time 9 minutesLast updated 10 days ago
Domain reload is the code reload mechanism used by the Mono scripting backend. For more information on when the Unity Editor performs code reload and how your code can hook into that process via callbacks, refer to Code reload and the code lifecycle.
You can configure the Editor to perform domain reload on entering Play mode to reset the application state. Resetting state before entering Play mode is often desirable so your application starts up as it would at the beginning of a new build. For example, static counters that were incremented in a previous Play mode session should begin from zero again in the next one.
However, domain reload is also a time-consuming operation that negatively impacts iteration times when you frequently switch between Edit and Play mode. For this reason, the Editor doesn't perform domain reload on entering Play mode by default. If you choose to keep the default configuration with domain reload off, you must then reset static state in some other way.
Effects of entering Play mode with domain reload off
If you keep Unity's default setting with domain reload off:
- Non-serialized fields keep the values assigned to them during Play mode on returning to Edit mode. This applies for fields of all script types, including MonoBehaviours (including those on prefab assets), ScriptableObjects, and your own custom C# types. For detailed information on what is and isn't serialized in different contexts, refer to Serialization rules.
- Static variables keep their values between Play mode sessions.
- Static events keep their registered subscribers between Play mode sessions.
- There are no additional or
OnDisablecalls for scripts marked with theOnEnableor[ExecuteInEditMode].[ExecuteAlways]
To compensate for this persistence of data between Play mode sessions and enter Play mode with a fresh application state, you must reset state in your code.
For more information on the effects of both domain and scene reload being off, refer to Domain and scene reload execution order reference.
Resetting state from code
When domain reloading is off, the values of static fields and the handlers assigned to static events persist between Play mode runs. The following code example has a static counter that increments on a press of any keyboard key.
With domain reload on, Unity reinitializes this code on entering Play mode, erasing the state from the previous Play mode run, including the counter value. With domain reload off, the counter value is preserved from the previous run. On the next run of Play mode, the counter begins with the value it had at the end of the previous run.
// Copy-paste this code into a MonoBehaviour script attached to a GameObject in your project.// Run it with domain reload enabled and then with domain reload disabled and note the different behavior.using UnityEngine;public class StaticsReset : MonoBehaviour{ // With domain reload disabled this counter won't reset to zero on exiting Play mode static int counter = 0; void Update() { if (Input.anyKeyDown) { counter++; Debug.Log("Counter: " + counter); } }}
You can fix the problem behavior with code that explicitly resets the counter between Play mode runs. You can either do this manually by writing code to reset the counter on entry to or exit from Play mode, or you can use the static cleanup attributes to have this done for you automatically on entry to Play mode.
Manual reset of static state
You can manually reset static state on entry to or exit from Play mode using the lifecycle attributes and respectively. It's often most efficient to reset state on exiting Play mode rather than on entering. The following example resets a static counter on exiting Play mode:
[OnEnteringPlayMode][OnExitingPlayMode]using UnityEngine;public class ManualStaticsReset : MonoBehaviour{ static int counter = 0; public static void ResetCounter() => counter = 0; // Update is called once per frame void Update() { if (Input.anyKeyDown) { counter++; Debug.Log("Counter: " + counter); } }}public static partial class PlayModeManager{ [OnEnteringPlayMode] static void Init() { Debug.Log("Entering Play mode!"); } [OnExitingPlayMode] private static void OnExitPlayMode() { Debug.Log("Resetting counter."); // Reset the counter so it starts from 0 on the next Play mode run ManualStaticsReset.ResetCounter(); Debug.Log("Exiting Play mode!"); }}
If your code executes in Edit mode in addition to Play mode, you can't rely on resetting state on exiting Play mode. Your code might modify a static variable while in Edit mode, so you must reset the variable on entering Play mode instead.
Automatic reset of static state
The and attributes use code generation to reset static state automatically on entering Play mode. You can apply them to static fields to specify that the field should or should not be automatically reset on entering Play mode.
[AutoStaticsCleanup][NoAutoStaticsCleanup]The following example shows how to use these attributes:
using Unity.Scripting.LifecycleManagement;using UnityEngine;public partial class AutomaticStaticsReset : MonoBehaviour{ [AutoStaticsCleanup] public static int cleanedUpCounter = 0; [NoAutoStaticsCleanup] public static int counter = 0; void Start() { Debug.Log(cleanedUpCounter); // Counter value is reset each time entering Play Mode Debug.Log(counter); // Counter value is only reset on Domain Reload cleanedUpCounter++; counter++; }}
Automatic statics cleanup is supported by code generation and a code analyzer. When you apply the code generator generates the necessary cleanup code.
[AutoStaticsCleanup]Choosing the right attribute
The following table provides guidance on which attribute to use for common field types. These are general guidelines based on typical usage patterns; you might encounter cases that require different choices based on your specific implementation.
Field Type | Typical Choice | Reason |
|---|---|---|
| Events, delegates | | Event handlers should be reset between Play mode sessions to avoid stale references. |
Collections of user objects (for example, | | User objects should not persist across Play mode sessions. |
ID generation counters (for example, | | Counters for unique name generation should persist to maintain uniqueness across Play mode sessions. |
Cached UI resources ( | | Immutable UI resources are safe to reuse. |
References to Unity objects ( | | Unity objects should be reset for clean Play mode sessions. |
Code generation for the static cleanup attributes is on by default. If you don't want to use these attributes and prefer to write your own cleanup code instead, you can turn code generation off with a global config file.
The autostatics cleanup code analyzer analyzes the code in your assembly to provide guidance on which static variables need to be reset and how. This is especially useful when you have domain reload off and aren't using the static cleanup attributes, as it helps you identify which static variables need to be reset manually. Code analysis for the static cleanup attributes is off by default. You can turn it on with a global config file.
When enabled, the analyzer emits warnings with the prefix. The following table lists the warnings you're most likely to encounter:
UALCode | Description | Fix |
|---|---|---|
| A type contains static members that require lifecycle attributes. Each affected member also shows | Add |
| An | Check the compiler message for details. |
| A type with auto-cleaned-up static members must be marked | Add |
| A static member must be marked with | Add |
| A type with | Remove the static constructor, move initialization logic elsewhere, or use |
Code generation and analysis configuration
You can configure code generation and code analysis settings per assembly using a file alongside the assembly. To configure these settings, do as follows:
.globalconfig- Create an assembly definition file in your scripts folder.
- Create an file in the same folder.
<assemblyDefinitionName>.globalconfig - Turn code generation and the code analyzer on or off using the following flags in a file:
.globalconfig
Property | Description |
|---|---|
| Marks this file as an analyzer config file. Can be omitted, but if present this property must be set to |
| Enables code generation for automatic statics cleanup. This must be set to |
| Enables code analysis for automatic statics cleanup. The analyzer analyzes the code for static variables in your assembly that need resetting and provides information on how to do so. The default value is |
The following is an example of a file with a configuration that corresponds to the default settings:
.globalconfigis_global = true # enables Roslynbuild_property.UnityEnableAutoStaticsCleanupCodeGen = true # statics cleanup code generator onbuild_property.UnityEnableAutoStaticsCleanupAnalysis = false # statics cleanup analyzer off