# Unity 6.3 — Addressables **Last verified:** 2026-02-13 **Status:** Production-Ready **Package:** `com.unity.addressables` (Package Manager) --- ## Overview **Addressables** is Unity's advanced asset management system that replaces `Resources.Load()` with async loading, remote content delivery, and better memory control. **Use Addressables for:** - Async asset loading (non-blocking) - DLC and remote content - Memory optimization (load/unload on demand) - Asset dependency management - Large projects with many assets **DON'T use Addressables for:** - Tiny projects (overhead not worth it) - Assets needed immediately at startup (use direct references) --- ## Installation ### Install via Package Manager 1. `Window > Package Manager` 2. Unity Registry > Search "Addressables" 3. Install `Addressables` --- ## Core Concepts ### 1. **Addressable Assets** - Assets marked as "Addressable" (assigned unique keys) - Can be loaded by key at runtime ### 2. **Asset Groups** - Organize assets (e.g., "UI", "Weapons", "Level1") - Groups determine build settings (local vs remote) ### 3. **Async Loading** - All loading is async (non-blocking) - Returns `AsyncOperationHandle` ### 4. **Reference Counting** - Addressables tracks asset usage - Must manually release assets when done --- ## Setup ### 1. Mark Assets as Addressable 1. Select asset in Project window 2. Inspector > Check "Addressable" 3. Assign key (e.g., "Enemies/Goblin") **OR via script:** ```csharp #if UNITY_EDITOR using UnityEditor.AddressableAssets; using UnityEditor.AddressableAssets.Settings; AddressableAssetSettings.AddAssetEntry(guid, "MyAssetKey", "Default Local Group"); #endif ``` --- ### 2. Create Groups `Window > Asset Management > Addressables > Groups` - **Default Local Group**: Bundled with build - **Remote Group**: Hosted on server (CDN) --- ## Basic Loading ### Load Asset Async ```csharp using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; public class AssetLoader : MonoBehaviour { async void Start() { // ✅ Load asset asynchronously AsyncOperationHandle handle = Addressables.LoadAssetAsync("Enemies/Goblin"); await handle.Task; if (handle.Status == AsyncOperationStatus.Succeeded) { GameObject prefab = handle.Result; Instantiate(prefab); } else { Debug.LogError("Failed to load asset"); } // ⚠️ IMPORTANT: Release when done Addressables.Release(handle); } } ``` --- ### Load and Instantiate ```csharp async void SpawnEnemy() { // ✅ Load and instantiate in one step AsyncOperationHandle handle = Addressables.InstantiateAsync("Enemies/Goblin"); await handle.Task; GameObject enemy = handle.Result; // Use enemy... // ✅ Release when destroying Addressables.ReleaseInstance(enemy); } ``` --- ### Load Multiple Assets ```csharp async void LoadAllWeapons() { // Load all assets with label "Weapons" AsyncOperationHandle> handle = Addressables.LoadAssetsAsync("Weapons", null); await handle.Task; foreach (var weapon in handle.Result) { Debug.Log($"Loaded: {weapon.name}"); } Addressables.Release(handle); } ``` --- ## Asset Labels (Tags) ### Assign Labels 1. `Window > Asset Management > Addressables > Groups` 2. Select asset > Inspector > Labels > Add label (e.g., "Level1", "UI") ### Load by Label ```csharp // Load all assets with label "Level1" Addressables.LoadAssetsAsync("Level1", null); ``` --- ## Remote Content (DLC) ### Setup Remote Groups 1. Create new group: `Window > Addressables > Groups > Create New Group > Packed Assets` 2. Group Settings: - **Build Path**: `ServerData/[BuildTarget]` - **Load Path**: `http://yourcdn.com/content/[BuildTarget]` ### Build Remote Content 1. `Window > Asset Management > Addressables > Build > New Build > Default Build Script` 2. Upload `ServerData/` folder to CDN 3. Game loads assets from remote server --- ## Preloading / Caching ### Download Dependencies ```csharp async void PreloadLevel() { // Download all assets in group without loading into memory AsyncOperationHandle handle = Addressables.DownloadDependenciesAsync("Level1"); await handle.Task; // Now "Level1" assets are cached, load instantly Addressables.Release(handle); } ``` ### Check Download Size ```csharp async void CheckDownloadSize() { AsyncOperationHandle handle = Addressables.GetDownloadSizeAsync("Level1"); await handle.Task; long sizeInBytes = handle.Result; Debug.Log($"Download size: {sizeInBytes / (1024 * 1024)} MB"); Addressables.Release(handle); } ``` --- ## Memory Management ### Release Assets ```csharp // ✅ Always release when done Addressables.Release(handle); // ✅ For instantiated objects Addressables.ReleaseInstance(gameObject); ``` ### Check Reference Count ```csharp // Addressables uses reference counting // Asset is unloaded when refCount == 0 ``` --- ## Asset References (Inspector-Assigned) ### Use AssetReference ```csharp using UnityEngine.AddressableAssets; public class EnemySpawner : MonoBehaviour { // ✅ Assign in Inspector (drag & drop) public AssetReference enemyPrefab; async void SpawnEnemy() { AsyncOperationHandle handle = enemyPrefab.InstantiateAsync(); await handle.Task; GameObject enemy = handle.Result; // Use enemy... enemyPrefab.ReleaseInstance(enemy); } } ``` --- ## Scenes ### Load Addressable Scene ```csharp using UnityEngine.SceneManagement; async void LoadScene() { AsyncOperationHandle handle = Addressables.LoadSceneAsync("MainMenu", LoadSceneMode.Additive); await handle.Task; SceneInstance sceneInstance = handle.Result; // Scene loaded // Unload scene await Addressables.UnloadSceneAsync(handle).Task; } ``` --- ## Common Patterns ### Lazy Loading (Load on Demand) ```csharp Dictionary> loadedAssets = new(); async Task GetAsset(string key) { if (!loadedAssets.ContainsKey(key)) { var handle = Addressables.LoadAssetAsync(key); await handle.Task; loadedAssets[key] = handle; } return loadedAssets[key].Result; } ``` --- ### Cleanup on Scene Unload ```csharp void OnDestroy() { // Release all handles foreach (var handle in loadedAssets.Values) { Addressables.Release(handle); } loadedAssets.Clear(); } ``` --- ## Content Catalog Updates (Live Updates) ### Check for Catalog Updates ```csharp async void CheckForUpdates() { AsyncOperationHandle> handle = Addressables.CheckForCatalogUpdates(); await handle.Task; if (handle.Result.Count > 0) { Debug.Log("Updates available"); await Addressables.UpdateCatalogs(handle.Result).Task; } Addressables.Release(handle); } ``` --- ## Performance Tips - **Preload** frequently used assets at startup - **Release** assets immediately when not needed - Use **labels** to batch-load related assets - **Cache** remote content for offline use --- ## Debugging ### Addressables Event Viewer `Window > Asset Management > Addressables > Event Viewer` - Shows all load/release operations - Memory usage per asset - Reference counts ### Addressables Profiler `Window > Asset Management > Addressables > Profiler` - Real-time asset usage - Bundle loading stats --- ## Migration from Resources ```csharp // ❌ OLD: Resources.Load (synchronous, blocks frame) GameObject prefab = Resources.Load("Enemies/Goblin"); // ✅ NEW: Addressables (async, non-blocking) var handle = await Addressables.LoadAssetAsync("Enemies/Goblin").Task; GameObject prefab = handle.Result; ``` --- ## Sources - https://docs.unity3d.com/Packages/com.unity.addressables@2.0/manual/index.html - https://learn.unity.com/tutorial/addressables