Version: Unity 6.6 Alpha (6000.6)
Language : English
Configuring how Unity enters Play mode
Enter Play mode without scene reload

Enter Play mode without domain reload

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 OnDisable or OnEnable calls for scriptsA piece of code that allows you to create your own Components, trigger game events, modify Component properties over time and respond to user input in any way you like. More info
    See in Glossary
    marked with the [ExecuteInEditMode] or [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 sceneA Scene contains the environments and menus of your game. Think of each unique Scene file as a unique level. In each Scene, you place your environments, obstacles, and decorations, essentially designing and building your game in pieces. More info
See in Glossary
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 [OnEnteringPlayMode] and [OnExitingPlayMode] 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:

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.

Note: For scripts that execute in Edit mode, keeping domain reload off skips MonoBehaviour.OnDisable and turning scene reload off skips MonoBehaviour.OnDestroy, which makes these methods inappropriate for resetting state in such scripts. For more information, refer to Domain and scene reload execution order reference.

Automatic reset of static state

The [AutoStaticsCleanup] and [NoAutoStaticsCleanup] 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.

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++;
    }
}

Note: For more information on the specific reset behavior applied for different C# types, refer to the [AutoStaticsCleanup] API reference.

Automatic statics cleanup is supported by code generation and a code analyzer. When you apply [AutoStaticsCleanup] the code generator generates the necessary cleanup code.

Important: Inline initializers (for example, static MyType s_Field = new MyType()) compile to static constructors, which run only once, when the type is first accessed. With domain reload off, this means they run once per Editor session, not once per Play mode session. If you mark such a field with [AutoStaticsCleanup], it resets to default on Play mode transitions but is not re-initialized. Ensure you have code to reinitialize the field, or use [NoAutoStaticsCleanup] if cleanup isn’t needed.

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 [AutoStaticsCleanup] Event handlers should be reset between Play mode sessions to avoid stale references.
Collections of user objects (for example, List<MonoBehaviour>) [AutoStaticsCleanup] User objects should not persist across Play mode sessions.
ID generation counters (for example, s_NextObjectID) [NoAutoStaticsCleanup] Counters for unique name generation should persist to maintain uniqueness across Play mode sessions.
Cached UI resources (GUIStyle, GUIContent) [NoAutoStaticsCleanup] ImmutableYou cannot change the contents of an immutable (read-only) package. This is the opposite of mutable. Most packages are immutable, including packages downloaded from the package registry or by Git URL.
See in Glossary
UI resources are safe to reuse.
References to Unity objects (ScriptableObject, MonoBehaviour) [AutoStaticsCleanup] 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 UAL prefix. The following table lists the warnings you’re most likely to encounter:

Code Description Fix
UAL0010 A type contains static members that require lifecycle attributes. Each affected member also shows UAL0013. Add [AutoStaticsCleanup] or [NoAutoStaticsCleanup] to each member.
UAL0011 An [AutoStaticsCleanup] or [NoAutoStaticsCleanup] configuration is invalid. Check the compiler message for details.
UAL0012 A type with auto-cleaned-up static members must be marked partial to allow the code generator to inject cleanup code. Add partial keyword to the class or struct.
UAL0013 A static member must be marked with [AutoStaticsCleanup] or [NoAutoStaticsCleanup]. Add [AutoStaticsCleanup] or [NoAutoStaticsCleanup] to the member.
UAL0014 A type with [AutoStaticsCleanup] members has an explicit static constructor. Remove the static constructor, move initialization logic elsewhere, or use [NoAutoStaticsCleanup] instead if cleanup isn’t required.

Code generation and analysis configuration

You can configure code generation and code analysis settings per assembly using a .globalconfig file alongside the assembly. To configure these settings, do as follows:

  1. Create an assembly definition file in your scripts folder.
  2. Create an <assemblyDefinitionName>.globalconfig file in the same folder.
  3. Turn code generation and the code analyzer on or off using the following flags in a .globalconfig file:
Property Description
is_global Marks this file as an analyzer config file. Can be omitted, but if present this property must be set to true. The default value is true.
build_property.UnityEnableAutoStaticsCleanupCodeGen Enables code generation for automatic statics cleanup. This must be set to true to use the [AutoStaticsCleanup] and [NoAutoStaticsCleanup] attributes. The default value is true.
build_property.UnityEnableAutoStaticsCleanupAnalysis 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 false.

The following is an example of a .globalconfig file with a configuration that corresponds to the default settings:

is_global = true # enables Roslyn
build_property.UnityEnableAutoStaticsCleanupCodeGen = true # statics cleanup code generator on
build_property.UnityEnableAutoStaticsCleanupAnalysis = false # statics cleanup analyzer off

Important: For packages, place the .globalconfig file in the same folder as the .asmdef file, creating the .globalconfig if it doesn’t exist. For scripts without an assembly definition, place it in a subfolder under Assets/. If you’re happy with the default configuration of code generation on and code analysis off, you don’t need to create this file and can simply begin using the static cleanup attributes in your code.

Additional resources

Configuring how Unity enters Play mode
Enter Play mode without scene reload