【Unity】Getting Started with Unity Addressables: Dramatically Improve Asset Management and Memory Efficiency

Created: 2026-02-05

Learn how to use Unity's official asset management system, Addressables. Automate complex AssetBundle management to easily reduce build sizes and deliver downloadable content.

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.

  1. From the Unity Editor menu, select "Window" > "Package Manager"
  2. Select "Unity Registry" from the dropdown menu in the upper left
  3. Find "Addressables" in the list and click on it
  4. 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.

  1. Select an asset in the Project window
  2. Check the "Addressable" checkbox in the Inspector
  3. 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 void is 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 ReleaseInstance also automatically destroys the spawned GameObject. Even if you manually Destroy the object, you should still call ReleaseInstance to 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 ModeDescriptionUse Case
Use Asset Database (fastest)Loads directly from the AssetDatabaseFast iteration during development
Simulate Groups (advanced)Simulates AssetBundlesVerifying dependencies and memory management
Use Existing BuildUses actual AssetBundlesTesting 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

  1. Select Window > Asset Management > Addressables > Event Viewer
  2. Run the game in Play Mode
  3. 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 OnDestroy or OnDisable
  • 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.

Further Learning