# Upgrade to Unity 6.6

> Upgrade a project from Unity 6.5 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](#cameras)
* [Editor and workflow](#editor)
* [Graphics](#graphics)
* [Optimization](#optimization)
* [Platforms](#platforms)
* [Programming](#programming)
* [UI Toolkit](#ui-toolkit)

## 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](https://docs.unity3d.com/Packages/com.unity.cinemachine@3.1/manual/CinemachineUpgradeFrom2.html). 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`](/engine/6000.6/script-reference/unityeditor/assetdatabase/forcereserializeassets.md) 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](/engine/6000.6/manual/analysis/graphics-performance-profiling/reduce-draw-calls/optimizing-draw-calls-choose-method.md).

### 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`:

   ```lang-csharp
   [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:

   ```lang-csharp
   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](https://discussions.unity.com/t/new-shader-preprocessor/768416).

### Deprecated Progressive CPU Lightmapper

The Progressive CPU Lightmapper is now deprecated and will be removed in a future release. Existing projects can continue to bake with it, but the recommended best practice is to migrate to the Unity Compute Light Baker or the Progressive GPU Lightmapper.

Baked lighting might look different after you change the backend, so review and adjust your lighting setup after you migrate. For more information, refer to [Choose a light baking backend](/engine/6000.6/manual/lighting-overview/direct-and-indirect-lighting/lightmapping/baking-before-runtime/configure/progressive-lightmapper.md) and [Unity Compute Light Baker](/engine/6000.6/manual/lighting-overview/direct-and-indirect-lighting/lightmapping/baking-before-runtime/configure/unity-compute-light-baker.md).

## 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** > Editor > **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](/engine/6000.6/manual/building-and-publishing/managed-code-variants.md#managed-code-variant).

  * `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`](/engine/6000.6/script-reference/unityeditor/playersettings/getmanagedcodevariant.md) and [`PlayerSettings.SetManagedCodeVariant`](/engine/6000.6/script-reference/unityeditor/playersettings/setmanagedcodevariant.md).
  * 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:

   ```lang-csharp
   #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`:

   ```lang-csharp
   #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:

     ```lang-csharp
     #if UNITY_EDITOR || DEVELOPMENT_BUILD
         SafetyChecks.CheckAlignmentAndThrow(ptr, nameof(ptr));
     #endif
     ```

     Replace the condition with `UNITY_ENABLE_CHECKS`:

     ```lang-csharp
     #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`:

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

     Replace the symbol in the attribute:

     ```lang-csharp
     [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:

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

     Replace the compile-time check with the runtime check:

     ```lang-csharp
     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:

```lang-csharp
#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:

```lang-csharp
#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](/engine/6000.6/manual/building-and-publishing/managed-code-variants.md), [`ManagedCodeVariant`](/engine/6000.6/script-reference/unityeditor/managedcodevariant.md), and the [Unity scripting symbol reference](/engine/6000.6/manual/programming-environment/script-compilation/conditional-compilation/scripting-symbol-reference.md) 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 the full procedure, refer to [Migrate a custom dictionary solution to built-in dictionary serialization](/engine/6000.6/manual/programming-environment/code-reload-serialization/script-serialization/dictionaries-migrate.md).

For more information, refer to [Dictionary serialization](/engine/6000.6/manual/programming-environment/code-reload-serialization/script-serialization/dictionaries.md).

## 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 causes a compile error in projects that call it. To fix the error, remove any calls to that method from your project. You do not need to replace them 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](/engine/6000.6/manual/uitoolkits/uielements/uie-migration-guides/migrate-custom-control.md), [Custom controls](/engine/6000.6/manual/uitoolkits/uielements/uie-structure-ui/uie-custom-controls.md) documentation and [`UxmlElementAttribute` API reference](/engine/6000.6/script-reference/unityengine/uielements/uxmlelementattribute.md).

## Additional resources

* [New in Unity](/engine/6000.6/manual/whats-new.md)
* [Upgrade Unity](/engine/6000.6/manual/upgrade-guides.md)
* [System requirements](/engine/6000.6/manual/get-started/install-and-upgrade/getting-started-installing-unity/system-requirements.md)
* [Install Unity](/engine/6000.6/manual/get-started/install-and-upgrade/getting-started-installing-unity.md)
* [Upgrade your Unity project](/engine/6000.6/manual/upgrade-guides/upgrade-project.md)
