Version: Unity 6.6 (6000.6)
Language : English
API updater
Upgrade to Unity 6.5

Upgrade to Unity 6.6

This page lists changes in Unity 6.6 (6000.6) in these areas that can affect existing projects when you upgrade from Unity 6.5 (6000.5) to Unity 6.6 (6000.6):

Cameras

This section outlines recent updates to the camera system that can affect your upgrade experience.

Cinemachine 3 is a core package

The com.unity.cinemachine package is now a core package and part of the Unity Editor. Any project that depends on this package will automatically upgrade to the version that is part of the Editor.

If your project uses Cinemachine 3, this change doesn’t affect you. If your project uses Cinemachine 2, Unity automatically updates it to use Cinemachine 3.

Cinemachine 3 is a major version change with a different API and data format.

To transition to Cinemachine 3, refer to Upgrade a Project from Cinemachine 2.x. To continue using Cinemachine 2, you must update the manifest of your project to reference a local copy of Cinemachine 2.

Editor and workflow

This section outlines recent updates to the Unity Editor and its general workflows that can affect your upgrade experience.

YAML file format change

Word wrapping is disabled in YAML text files and the Reduce Version Control Noise option has been removed from the Unity Editor settings.

Reduce Version Control Noise was previously enabled by default, which disabled word wrapping of references in YAML files. Because of this, most projects already had word wrapping disabled.

The equivalent API, serializeInlineMappingsOnOneLine setter is now a no-op and the getter always returns true.

The impact of this change is that you might see changes to YAML files that appear unrelated to any changes you made to your assets.

To prevent multiple contributors from experiencing these changes, consider reserializing all your assets. For more information, refer to the ForceReserializeAssets API.

Graphics

This section outlines recent updates to graphics that can affect your upgrade experience.

Removed dynamic batching

Dynamic batching is now obsolete. For information about other methods of optimizing draw calls, refer to Choose a method for optimizing calls.

Render Pipeline Core no longer depends on Terrain

Removed the dependency on com.unity.modules.terrain package from the com.unity.render-pipelines.core package. If your project relies on Terrain indirectly through the Render Pipeline Core, Universal Render Pipeline, or High Definition Render Pipeline packages, add the com.unity.modules.terrain package to your project through the Package Manager > Built-in tab. Terrain is still included in new projects’ dependencies by default.

Removed Rendering Debugger legacy state management

The legacy Debug UI infrastructure in the com.unity.render-pipelines.core package is now obsolete. Using these APIs now triggers an [Obsolete(..., true)] attribute, resulting in compilation errors. This change affects DebugState, DebugState<T>, legacy DebugUIDrawer implementations, and their associated types. You must migrate any projects using these features to the current Rendering Debugger pattern.

The following APIs no longer compile:

  • Debug State classes: DebugState, DebugState<T>, and all concrete implementations (such as DebugStateBool, DebugStateInt, DebugStateFloat, DebugStateColor, and DebugStateVector variants).
  • Legacy Debug UI Drawers: All older DebugUIDrawer custom drawer implementations.
  • Supporting types: DebugStateAttribute and LegacyStyles.

To upgrade your code, follow these steps:

  1. Implement ISerializedDebugDisplaySettings on your debug settings classes.
    If your debug settings class previously relied on DebugState for serialization, you must now implement ISerializedDebugDisplaySettings. This interface allows for automatic serialization via the DebugDisplaySerializer.

    The following example demonstrates implementing ISerializedDebugDisplaySettings:

    [Serializable]
    public class MyDebugSettings : IDebugDisplaySettingsData, ISerializedDebugDisplaySettings
    {
        public bool myFeatureEnabled;
    
        void IDebugDisplaySettingsData.Reset()
        {
            myFeatureEnabled = false;
        }
    }
    
  2. Implement the Create method for custom DebugUI.Widget implementations.
    Custom widgets that formerly used DebugUIDrawer for rendering must now implement the abstract Create method to return their VisualElement.

    The following example demonstrates a custom DebugUI.Widget implementation with the Create method:

    public class MyCustomWidget : DebugUI.Widget
    {
        protected override VisualElement Create()
        {
            var container = new VisualElement();
            // Use UI Toolkit to build your UI here
            return container;
        }
    }
    

The Rendering Debugger now handles ToVisualElement calls internally, which in turn executes your defined Create logic.

Surface shader code generation now uses caching preprocessor

Surface shader code generation now uses the caching preprocessor. For information about the preprocessor behavior changes, refer to the New shader preprocessor Discussions post.

Optimization

This section outlines recent updates to optimization that can affect your upgrade experience.

Performance testing API is a core package

The com.unity.test-framework.performance package is now a core package and part of the Unity Editor. Any project that depends on this package now automatically uses the version that is part of the Editor.

Platforms

This section outlines recent updates to platform-specific tools and settings that can affect your upgrade experience.

Android

This section outlines recent updates to Android-specific tools and settings.

Removed Legacy and Round icons

Removed support for Legacy and Round Android icons. Unity now supports only Adaptive Android icons.

When you upgrade a project that uses Legacy and Round Android icons, Unity displays a warning message and excludes these icons from Android builds.

To update your icon settings, follow these steps:

  1. Open Edit > Project Settings > Player > Android > Icon.
  2. Verify your Adaptive icon settings.

You can remove any unused Legacy and Round icon assets from your project. The warning clears when you open the Player settings.

Removed legacy chained signal handler behavior on Android

The legacy option for the -androidChainedSignalHandlerBehavior command-line argument has been removed from the Android Player runtime. This option was added as a workaround for older Android versions that didn’t handle native crash reporting. This behavior handled native crashes, such as SIGSEGV at JNI boundaries using setjmp and longjmp functions, and wrapped them into Java exceptions. This approach is now obsolete because app stores, such as the Google Play Console, now handle native crashes directly. Furthermore, this legacy behavior prevented third-party crash-reporting SDKs, such as Firebase Crashlytics or Bugsnag, from receiving signals. This caused background worker threads to stop responding upon crashing.

In Unity 6.6, the legacy option has been fully removed. If you explicitly pass legacy as a command-line argument, Unity now does the following:

  1. Logs an error to Logcat: ChainedSignalHandler: Legacy behavior has been removed. The default chained signal handler behavior will be used instead.
  2. Uses the default chained signal handler behavior instead of the legacy behavior.

Refer to the following based on your project setup:

  • Command-line fallback: If your build pipelines, launch scripts, or custom Activity templates still pass -androidChainedSignalHandlerBehavior legacy, Unity doesn’t fail to boot and automatically falls back to the default behavior. However, it logs an error in Logcat. Remove this obsolete argument to keep your logs clean.
  • Java exception handling: If your application framework relied on capturing native crashes inside Java try/catch blocks at the JNI boundary, the legacy behavior is no longer available. Native crashes now terminate the process and are handled as standard native signals.
  • Crash reporting and multithreading: Native crash handlers, including Unity Cloud Diagnostics and third-party tools, now capture native crashes across all threads. This includes background worker threads and Java-invoked threads, which previously didn’t report crashes.

Raised minimum supported OpenGL ES version for Android from GLES 3.0 to GLES 3.1

The minimum OpenGL ES version on Android is now ES 3.1, raised from ES 3.0.

When you select OpenGL ES3 in the Android Graphics API list, the following occurs:

  • The generated manifest declares <uses-feature android:glEsVersion="0x00030001" />.
  • The Player no longer creates an ES 3.0 context at runtime.
  • Devices that support only ES 3.0 and do not support Vulkan can no longer run the app, as the Play Store filters them out and initialization fails on-device.

You cannot revert to ES 3.0.

PlayerSettings.openGLRequireES31 is deprecated. The getter always returns true, the setter is a no-op. Referencing the property raises an obsolete warning, which becomes a build error under warnings-as-errors. The Require ES3.1 property is replaced with Use OpenGL ES 3.0 shaders in Player > Android > Other Settings.

For compatibility reasons, if your project never used Require ES3.1 or similar, the upgraded project automatically enables Use OpenGL ES 3.0 shaders. This gives you the option to upgrade OpenGL ES 3.0 shaders to version 3.1 as needed, preventing visual artifacts that might otherwise occur if Unity forced OpenGL ES 3.1 shaders. For example, OpenGL ES 3.1 shaders raise the MAX_VISIBLE_LIGHTS limit from 16 to 32, which increases the application’s workload. The Use OpenGL ES 3.0 shaders setting provides a transition period so you can adapt to these changes without causing performance regressions in your upgraded project.

To update your code for this change, follow these steps:

  1. Remove calls to PlayerSettings.openGLRequireES31. ES 3.1 is now implied whenever OpenGL ES3 is selected.
  2. Disable Player > Android > Other Settings > Use OpenGL ES 3.0 shaders to use SHADER_API_GLES31 shader keyword instead of SHADER_API_GLES30.
  3. To require a higher version, use PlayerSettings.openGLRequireES31AEP or openGLRequireES32, or enable the Require ES3.1+AEP or Require ES3.2 checkboxes in Player > Android > Other Settings.

Programming

This section outlines recent updates to the Programming system that can affect your upgrade experience.

UNITY_64 and DEVELOPMENT_BUILD scripting symbols are deprecated

The UNITY_64 and DEVELOPMENT_BUILD preprocessor symbols are deprecated, and C# diagnostics now follow the Managed Code Variant setting. These updates involve the following:

  • Added a new Managed Code Variant setting. This per-platform setting controls which diagnostic defines are emitted into your C# code, independently of the native binary. To access it, go to Edit > Project Settings > Player > Other Settings > Managed Code Variant. For a list of the variants and the defines they emit, refer to Adding diagnostics to C# code.

    • UNITY_ENABLE_CHECKS replaces the extra safety checks and assertions meaning of DEVELOPMENT_BUILD, and UNITY_INCLUDE_INSTRUMENTATION replaces the profiling and diagnostic logging meaning. This enables profiling without any diagnostics checks.
    • The variant can also be read or set from build scripts with PlayerSettings.GetManagedCodeVariant and PlayerSettings.SetManagedCodeVariant.
    • In the Editor, both UNITY_ENABLE_CHECKS and UNITY_INCLUDE_INSTRUMENTATION are always defined. UNITY_ASSERTIONS and ENABLE_PROFILER have historically been defined for development builds, and continue to be defined during this transitional period.
  • Deprecated UNITY_64 and DEVELOPMENT_BUILD scripting symbols. Using either symbol in an #if directive or a [Conditional(...)] attribute now raises a Roslyn analyzer warning (UAC0008 for UNITY_64, UAC0009 for DEVELOPMENT_BUILD) in the Console and in your IDE.

Impact of not updating your code

In Unity 6.6, the UNITY_64 and DEVELOPMENT_BUILD defines continue to work. Unity displays deprecation warnings but DEVELOPMENT_BUILD is still emitted for development builds, so your project still works at runtime. However, if your assemblies are compiled with warnings as errors, the warnings become build errors immediately.

In Unity 6.8, these defines will be fully removed. Using them will become a hard compilation error and DEVELOPMENT_BUILD will no longer be emitted by the compilation pipeline. If you migrate now, you can update your codebase incrementally.

Behavior impact in your project

If you never used these defines, your project is still impacted by these changes. Many built-in features and packages previously used DEVELOPMENT_BUILD internally and now use the Managed Code Variant setting instead. Unity includes these features based on the option you set for Managed Code Variant, instead of the Development Build setting. The default option is Release, which defines none of the diagnostic symbols, so a Development Build using the default variant no longer contains these diagnostics. The affected features include the following:

  • Scriptable Render Pipeline (URP/HDRP/Core): Debug overlays, Rendering Debugger runtime resources, Render Graph Viewer, render-graph validation, the magenta incompatible objects pass, Frame Debugger support, and the Volume panel are now gated by UNITY_ENABLE_CHECKS (Debug/Checked). Render Graph profiling samplers, URP’s per-pass ScriptableRenderPass.profilingSampler, and HDRP’s dynamic-resolution overlay are gated by UNITY_INCLUDE_INSTRUMENTATION (Debug/Checked/Instrumented). Build-time stripping of debug shaders and rendering-debugger resources now follows the variant too, so a non-development Checked build keeps them and a Release build strips them. As a side effect, non-development Release builds no longer ship debug-display shader variants they previously included, reducing build size and shader-variant count.
  • Unity Physics: Simulation integrity checks are now compiled in for the Debug/Checked variants. You can still override the checks with UNITY_PHYSICS_DISABLE_INTEGRITY_CHECKS.
  • Entities: Entities Journaling, the data behind the Entities Journaling window, is now compiled in for Debug, Checked, and Instrumented variants. You can still override it with DISABLE_ENTITIES_JOURNALING.
  • Adaptive Performance: Apple and Android provider logging is now available in Debug, Checked, and Instrumented variants.

To achieve the diagnostic behavior that a Development Build previously provided, set the Managed Code Variant to Checked (which enables both the check and instrumentation paths) for the platforms where you enable the Development Build checkbox. Use Debug if you also want DEBUG and unoptimized code for stepping through with a debugger.

If you have a custom Scriptable Render Pipeline with build processors that read CoreBuildData.developmentBuild, this property is now [Obsolete] and always returns false. Use CoreBuildData.useDiagnosticChecks instead.

Update your code

  1. Replace UNITY_64. The bitness of the native binary is not known when scripts are compiled, so replace any compile-time #if UNITY_64 with a runtime check on IntPtr.Size (8 = 64-bit, 4 = 32-bit), or with bitness-independent code.

    For example, the following code uses UNITY_64 at compile time:

    #if !UNITY_64 && UNITY_ANDROID
        return HashWithoutUnalignedLoads(buffer, length);
    #else
        return HashWithUnalignedLoads(buffer, length);
    #endif
    

    Replace it with the following runtime check on IntPtr.Size:

    #if UNITY_ANDROID
        if (IntPtr.Size == 4)
            return HashWithoutUnalignedLoads(buffer, length);
    #endif
        return HashWithUnalignedLoads(buffer, length);
    
  2. Replace DEVELOPMENT_BUILD:

    • If the code was for safety checks, validation, assertions: use #if UNITY_ENABLE_CHECKS (Debug/Checked).

      For example, the following check runs only in the Editor or a development build:

      #if UNITY_EDITOR || DEVELOPMENT_BUILD
          SafetyChecks.CheckAlignmentAndThrow(ptr, nameof(ptr));
      #endif
      

      Replace the condition with UNITY_ENABLE_CHECKS:

      #if UNITY_ENABLE_CHECKS
          SafetyChecks.CheckAlignmentAndThrow(ptr, nameof(ptr));
      #endif
      

    Compound gates such as #if UNITY_EDITOR || DEVELOPMENT_BUILD become #if UNITY_EDITOR || UNITY_ENABLE_CHECKS. Because the Editor already defines the new symbols, you can usually drop the redundant UNITY_EDITOR || part.

    • If the code was for profiler instrumentation, debug names, or diagnostic logging: use #if UNITY_INCLUDE_INSTRUMENTATION (Debug/Checked/Instrumented), or layer it onto a [Conditional] attribute:

      For example, the following method is conditional on DEVELOPMENT_BUILD:

      [Conditional("DEVELOPMENT_BUILD")]
      public static void LogDiagnostic(string message) { ... }
      

      Replace the symbol in the attribute:

      [Conditional("UNITY_INCLUDE_INSTRUMENTATION")]
      public static void LogDiagnostic(string message) { ... }
      
    • A runtime check for a development Player: use the runtime property Debug.isDebugBuild. This is the correct choice when the new variant defines are not equivalent. For example, a non-development Player can ship with the Checked variant, so a #if UNITY_ENABLE_CHECKS block would compile sensitive code, such as logging that might leak authentication tokens, into a production build.

      For example, the following log call previously shipped only in the Editor or a development build:

      #if UNITY_EDITOR || DEVELOPMENT_BUILD
          Debug.LogError($"Rejecting connection: {payload}");
      #endif
      

      Replace the compile-time check with the runtime check:

      if (Debug.isDebugBuild)
          Debug.LogError($"Rejecting connection: {payload}");
      
  3. Choose the Managed Code Variant for each platform: In Edit > Project Settings > Player > Other Settings > Managed Code Variant, select the variant whose diagnostics you want in your Player builds (Release for shipping; Checked or Debug while developing). From a build script, call PlayerSettings.SetManagedCodeVariant(namedBuildTarget, ManagedCodeVariant.Checked).

  4. Replace BuildOptions.ForceEnableAssertions: This enum value is now [Obsolete]. Use PlayerSettings.SetManagedCodeVariant(namedBuildTarget, ManagedCodeVariant.Checked) instead.

To make sure your code compiles against multiple Unity versions

For package and Asset Store authors whose code also targets Unity versions older than 6.6, where the new defines don’t exist, gate on UNITY_6000_6_OR_NEWER and fall back to a runtime Debug.isDebugBuild check. This lets you keep the diagnostic body written once:

#if !UNITY_6000_6_OR_NEWER || UNITY_ENABLE_CHECKS
#if !UNITY_6000_6_OR_NEWER
    if (Debug.isDebugBuild)
#endif
    {
        // diagnostic body, written exactly once
        if (library == null)
            Debug.LogWarning("No library assigned.");
    }
#endif

For [Conditional] methods, select the attribute per Unity version:

#if UNITY_6000_6_OR_NEWER
[Conditional("UNITY_INCLUDE_INSTRUMENTATION")]
#else
[Conditional("DEVELOPMENT_BUILD")]
#endif
static void LogDiagnostic(...) { ... }

For more information, refer to Adding diagnostics to C# code, ManagedCodeVariant, and the Unity scripting symbol reference documentation.

Dictionary serialization works alongside existing dictionary solutions

Unity 6.5 and earlier versions didn’t support serializing fields declared as Dictionary<TKey, TValue>. A common alternative solution was a wrapper type that derives from it, or a [Serializable] class that stores parallel key and value lists and rebuilds the dictionary in ISerializationCallbackReceiver.OnAfterDeserialize.

Unity 6.6 serializes a field whose declared type is Dictionary<TKey, TValue> when it has [SerializeField]. A field whose declared type derives from Dictionary<TKey, TValue>, or wraps it in another class, remains a regular serialized class handled by the callback code it already uses. Those solutions keep working without changes, whether the type is one you wrote or one that comes from a package. You can use serialized dictionaries in new code and leave your existing fields as they are.

If you choose to migrate a field to Unity’s dictionary serialization, you must migrate its data yourself. Add the new field alongside the old one, copy the data across from an editor script, and delete the old field only after you have checked the result. If you delete the old field first, its data is lost.

For more information, refer to Dictionary serialization.

UI Toolkit

This section outlines recent updates to Unity’s UI Toolkit that can affect your upgrade experience.

Removed DefaultEventSystem.LegacyInputProcessor

The DefaultEventSystem.LegacyInputProcessor has been removed. As a result, the obsolete method UIToolkitInputConfiguration.SetRuntimeInputBackend now produces an error in projects that use it. You can safely ignore this error, but remove any remaining calls to that method from your project. You do not need to replace it with anything, as the method no longer has an effect.

Removed UXML Factory/Traits

In Unity 6.0, UI Toolkit introduced a modern UI element authoring system based on UxmlElement and UxmlAttribute, powered by Unity serialization. This new system replaces the legacy UXML Factory/Traits workflow, which was deprecated and is now removed.

While the legacy system was supported for backward compatibility, maintaining dual workflows has created bugs, confusion, and long-term costs. The new system offers a cleaner, more robust, and consistent UI experience, so we’re moving forward with it exclusively.

For more information and examples, refer to Migrate custom controls from an earlier version to Unity 6, Custom controls documentation and UxmlElementAttribute API reference.

Additional resources

API updater
Upgrade to Unity 6.5