Overview
Tested with: Unity 2022.3 LTS / Unity 6
"The build size is too large..." "Memory management is too complex..." "I want to deliver downloadable content..."
These are common asset management challenges in Unity development. Addressables is Unity's official asset management system. Built on top of AssetBundles, it automates dependency management, memory management, and load source switching, making complex asset management straightforward.
Differences from AssetBundle
AssetBundle is a low-level system for compressing assets to reduce build size and delivering downloadable content. However, actually using AssetBundles required a lot of implementation work, including dependency management, memory management, and load source switching.
Addressables uses AssetBundles internally but automates all of this complexity. Developers simply assign an "address" to an asset and load it by that address.
Installation
Addressables can be installed from the Package Manager.
- From the Unity Editor menu, select "Window" > "Package Manager"
- Select "Unity Registry" from the dropdown menu in the upper left
- Find "Addressables" in the list and click on it
- Click the "Install" button in the lower right
Once installed, an "Addressable" checkbox will appear in asset Inspectors.
Making Assets Addressable
Method 1: Enable Addressable in the Inspector
The simplest way is to check the "Addressable" checkbox in the asset Inspector.
- Select an asset in the Project window
- Check the "Addressable" checkbox in the Inspector
- Set the address name (defaults to the asset path)
Method 2: Assign to an AssetReference Field
You can also make an asset Addressable by adding an AssetReference field to a MonoBehaviour or ScriptableObject and assigning the asset in the Inspector.
using UnityEngine;
using UnityEngine.AddressableAssets;
public class Example : MonoBehaviour
{
public AssetReference assetReference;
}
Loading Assets
Method 1: Load by Address String (Completed Callback)
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class LoadByAddress : MonoBehaviour
{
void Start()
{
Addressables.LoadAssetAsync<GameObject>("Enemy").Completed += OnLoadCompleted;
}
void OnLoadCompleted(AsyncOperationHandle<GameObject> handle)
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
GameObject prefab = handle.Result;
Instantiate(prefab);
}
else
{
Debug.LogError($"Failed to load asset: {handle.OperationException}");
}
}
}
Method 1.5: Load with async/await (Recommended)
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class LoadByAddressAsync : MonoBehaviour
{
private AsyncOperationHandle<GameObject> handle;
async void Start()
{
try
{
handle = Addressables.LoadAssetAsync<GameObject>("Enemy");
GameObject prefab = await handle.Task;
Instantiate(prefab);
}
catch (System.Exception e)
{
Debug.LogError($"Failed to load asset: {e.Message}");
}
}
void OnDestroy()
{
if (handle.IsValid())
Addressables.Release(handle);
}
}
Benefits of async/await: Avoids callback hell and makes error handling intuitive with try-catch.
Note:
async voidis a fire-and-forget pattern, meaning exceptions will not propagate to the caller. For production projects, consider using UniTask or Unity 6's Awaitable.
Method 2: Load with AssetReference
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class LoadByReference : MonoBehaviour
{
public AssetReference assetReference;
void Start()
{
assetReference.LoadAssetAsync<GameObject>().Completed += OnLoadCompleted;
}
void OnLoadCompleted(AsyncOperationHandle<GameObject> handle)
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
GameObject prefab = handle.Result;
Instantiate(prefab);
}
}
void OnDestroy()
{
assetReference.ReleaseAsset();
}
}
Method 2.5: Load and Instantiate Simultaneously with InstantiateAsync
InstantiateAsync lets you load and instantiate in a single step.
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class InstantiateExample : MonoBehaviour
{
public AssetReference assetReference;
private AsyncOperationHandle<GameObject> handle;
private GameObject spawnedObject;
void Start()
{
handle = assetReference.InstantiateAsync(transform.position, Quaternion.identity);
handle.Completed += OnInstantiateCompleted;
}
void OnInstantiateCompleted(AsyncOperationHandle<GameObject> op)
{
if (op.Status == AsyncOperationStatus.Succeeded)
{
spawnedObject = op.Result;
Debug.Log($"Instantiated: {spawnedObject.name}");
}
}
void OnDestroy()
{
// Unload objects instantiated with InstantiateAsync using ReleaseInstance
// This also destroys the spawned GameObject
if (handle.IsValid())
Addressables.ReleaseInstance(handle);
}
}
Lifecycle note: Calling
ReleaseInstancealso automatically destroys the spawned GameObject. Even if you manuallyDestroythe object, you should still callReleaseInstanceto release the handle.
Method 3: Load by Label
You can assign the same label to multiple assets and load them all at once by that label.
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using System.Collections.Generic;
public class LoadByLabel : MonoBehaviour
{
private List<GameObject> loadedPrefabs = new List<GameObject>();
private AsyncOperationHandle<IList<GameObject>> handle;
void Start()
{
handle = Addressables.LoadAssetsAsync<GameObject>(
"enemies",
prefab => {
// Called each time an asset is loaded
loadedPrefabs.Add(prefab);
Debug.Log($"Loaded: {prefab.name}");
}
);
handle.Completed += OnAllLoaded;
}
void OnAllLoaded(AsyncOperationHandle<IList<GameObject>> op)
{
if (op.Status == AsyncOperationStatus.Succeeded)
{
Debug.Log($"All {op.Result.Count} assets loaded.");
}
}
void OnDestroy()
{
Addressables.Release(handle);
}
}
Label naming convention: Use lowercase kebab-case or snake_case for label names (e.g.,
stage-1-assets,enemy_prefabs). Avoid uppercase letters and spaces.
Unloading Assets
Assets loaded with Addressables must always be unloaded. Failing to do so will cause memory leaks.
// When loaded by address string
Addressables.Release(handle);
// When loaded by AssetReference
assetReference.ReleaseAsset();
Choosing the Right Play Mode
Addressables offers three Play Modes.
| Play Mode | Description | Use Case |
|---|---|---|
| Use Asset Database (fastest) | Loads directly from the AssetDatabase | Fast iteration during development |
| Simulate Groups (advanced) | Simulates AssetBundles | Verifying dependencies and memory management |
| Use Existing Build | Uses actual AssetBundles | Testing in a production-like environment |
Practical Examples
Example 1: Dynamically Load and Instantiate a Prefab
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class SpawnEnemy : MonoBehaviour
{
public AssetReference enemyPrefab;
private AsyncOperationHandle<GameObject> handle;
void Start()
{
handle = enemyPrefab.LoadAssetAsync<GameObject>();
handle.Completed += OnLoadCompleted;
}
void OnLoadCompleted(AsyncOperationHandle<GameObject> op)
{
if (op.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(op.Result, transform.position, Quaternion.identity);
}
}
void OnDestroy()
{
enemyPrefab.ReleaseAsset();
}
}
Example 2: Dynamically Load a Scene
public AssetReference sceneReference;
public void LoadSceneAdditive()
{
sceneReference.LoadSceneAsync(LoadSceneMode.Additive);
}
Detecting Memory Leaks: Event Viewer
"Always unload" is critical with Addressables, but you need a way to verify that assets are actually being unloaded.
The Addressables Event Viewer lets you monitor loaded assets in real time.
Opening the Event Viewer
- Select
Window > Asset Management > Addressables > Event Viewer - Run the game in Play Mode
- Load/unload status is displayed in real time
What to Check
- Whether assets remain after scene transitions
- Whether the same asset is loaded multiple times
- Whether reference counts are decreasing correctly
Note: To use the Event Viewer, you need to enable "Send Profiler Events" in the Addressables settings.
Best Practices
- Group related assets - Keep related assets in the same group
- Use labels - Convenient for loading multiple assets at once
- Use AssetReference - Type-safe and allows direct asset assignment in the Inspector
- Always unload - Release assets in
OnDestroyorOnDisable - Choose the right Play Mode - Use Asset Database during development, Use Existing Build for final testing
- Verify with Event Viewer - Regularly check for memory leaks
Summary
Addressables is Unity's official asset management system. Built on top of AssetBundles, it automates dependency management, memory management, and load source switching.
- Easily switch load sources - Toggle between development and release with a single setting change
- Automatically resolve dependencies - Dependent AssetBundles are loaded automatically
- Automate memory management - Automatic memory management through reference counting
- Easily deliver downloadable content - Supports downloading from remote servers
Start using Addressables to achieve efficient asset management in your projects.