Unity Addressables for Beginners: Load, Release and Host Assets

Illustration of a cloud delivering glowing asset packages to a game controller

Written by

in

As a Unity project grows, two problems show up together: the build gets huge, and everything referenced by a scene loads into memory whether it’s needed or not. Addressables is Unity’s official answer to both. You give assets an address, load them by that address when you need them, release them when you don’t, and optionally host some of them on a server instead of shipping them in the build. This beginner guide covers setup, loading and releasing, AssetReference fields, labels, scenes, remote content, and the memory mistakes that catch almost everyone the first time.

Why Addressables?

Unity gives you three ways to get an asset into the game:

  • Direct references (a prefab dragged into a field). Simple, but everything a scene references loads with the scene and stays in memory.
  • The Resources folder (Resources.Load). Loads on demand, but everything in Resources ships in the build whether used or not, it slows startup, and Unity itself recommends against it for anything beyond prototypes.
  • Addressables. Load on demand by address, control what’s grouped into which bundle, release memory reliably, and move content to a server without code changes.

Addressables is worth it when you have lots of content that isn’t all needed at once: many levels, character skins, large audio, localized assets, or DLC. For a small game jam project, direct references are fine.

Installing and Setting Up

  1. Install Addressables from Window > Package Manager > Unity Registry.
  2. Open Window > Asset Management > Addressables > Groups and click Create Addressables Settings. This creates an AddressableAssetsData folder with a Default Local Group.
  3. Select any asset (a prefab, sprite or audio clip) and tick Addressable at the top of the Inspector. Or drag assets straight into a group in the Groups window.
  4. Each asset gets an address, by default its path such as Assets/Prefabs/Goblin.prefab. Right-click and use Simplify Addressable Names, or rename it to something short like Goblin.

Groups decide how assets are packed into asset bundles. Put things that load together in the same group (all of level 3’s props), and things that load separately in different groups.

Loading and Releasing Assets

Every load returns an AsyncOperationHandle. You wait for it to finish, use the result, and later release the handle. That last step is the one people forget.

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class EnemyLoader : MonoBehaviour
{
    AsyncOperationHandle<GameObject> handle;

    async void Start()
    {
        handle = Addressables.LoadAssetAsync<GameObject>("Goblin");
        GameObject prefab = await handle.Task;

        if (handle.Status == AsyncOperationStatus.Succeeded)
            Instantiate(prefab, Vector3.zero, Quaternion.identity);
    }

    void OnDestroy()
    {
        if (handle.IsValid())
            Addressables.Release(handle);   // frees the asset when nothing else uses it
    }
}

If you’d rather have Addressables create and track the instance for you, use InstantiateAsync, and destroy it with ReleaseInstance:

var op = Addressables.InstantiateAsync("Goblin", spawnPoint.position, Quaternion.identity);
GameObject goblin = await op.Task;

// Later, instead of Destroy(goblin):
Addressables.ReleaseInstance(goblin);

Addressables counts references. Loading the same address twice increases the count, and each load needs a matching release. The asset (and its bundle) is only unloaded when the count reaches zero.

AssetReference Fields

Typing addresses as strings is error-prone. AssetReference gives you an Inspector field that accepts drag-and-drop, like a normal reference, but doesn’t load the asset until you ask:

public class Spawner : MonoBehaviour
{
    [SerializeField] AssetReferenceGameObject enemyPrefab;
    [SerializeField] AssetReferenceT<AudioClip> spawnSound;

    async void SpawnWave()
    {
        for (int i = 0; i < 5; i++)
        {
            GameObject enemy = await enemyPrefab.InstantiateAsync(RandomPoint(), Quaternion.identity).Task;
        }
    }

    Vector3 RandomPoint() => transform.position + Random.insideUnitSphere * 5f;
}

Dragging a non-addressable asset into an AssetReference field marks it Addressable automatically. This is the easiest way to convert an existing project piece by piece.

Loading Groups with Labels

Labels tag many assets so you can load them together, like all “level1” assets or all “christmas” skins. Add labels in the Groups window, then:

var handle = Addressables.LoadAssetsAsync<Sprite>(
    "christmas",
    sprite => Debug.Log("Loaded " + sprite.name));   // callback per asset

IList<Sprite> sprites = await handle.Task;
// ... use them ...
Addressables.Release(handle);   // one release frees them all

Loading Scenes

Scenes can be addressable too, which means they don’t need to be in the Build Profile’s scene list, and a big level can be downloaded later.

var sceneHandle = Addressables.LoadSceneAsync("Level3", LoadSceneMode.Single);
await sceneHandle.Task;

// For an additive scene, unload it through Addressables too:
// await Addressables.UnloadSceneAsync(sceneHandle).Task;

Keep your very first scene (the bootstrap or splash scene) as a normal build scene. It then loads everything else through Addressables.

📦 How big will your build be?

Moving content into Addressables groups or onto a server is one of the best ways to shrink a WebGL or mobile download. Our free estimator shows roughly how much each asset type adds to a Web build.

Open the WebGL Build Size Estimator →

Building and Play Mode Scripts

Addressable content is built into asset bundles separately from the player. In the Groups window, the Play Mode Script dropdown controls how the Editor loads content:

  • Use Asset Database (fastest): loads straight from your project. Nothing needs building. Use it day to day.
  • Use Existing Build: loads from real built bundles, exactly like a player build. Use it before releasing, because it catches problems the fast mode hides (missing dependencies, wrong groups).

To build content, use Build > New Build > Default Build Script in the Groups window. By default, Addressables settings also build content automatically as part of a player build (the Build Addressables on Player Build option on the settings asset). If your built game can’t find addressable assets, check that option first.

Remote Content

To host content on a server or CDN (for DLC, or to keep the initial download small):

  1. On the AddressableAssetSettings asset, enable Build Remote Catalog.
  2. On the groups you want to host, set Build & Load Paths to Remote, and set the remote load path in your profile to your server URL.
  3. Build, then upload the contents of the ServerData folder to that URL.

Players download bundles the first time they’re needed, and they’re cached afterward. You can show a download size up front with Addressables.GetDownloadSizeAsync(key) and pre-download with DownloadDependenciesAsync. To ship content changes without a new app build, use Update a Previous Build with the addressables_content_state.bin file saved from the original build. Keep that file in version control.

Troubleshooting

InvalidKeyException: No Location found for Key=…

The address doesn’t exist. Check spelling and case in the Groups window. If it works in the Editor but not in a build, the content wasn’t built. Build it, or enable building on player build.

Memory keeps growing

Handles aren’t being released. Every LoadAssetAsync needs one Release, and every InstantiateAsync needs ReleaseInstance. Destroying an object created with InstantiateAsync using plain Destroy leaks its reference. The Addressables Event Viewer or Profiler module shows live reference counts.

The same texture is in memory twice

An asset that isn’t addressable but is used by assets in two different groups gets copied into both bundles. Make shared dependencies (materials, shared textures) addressable too, ideally in their own group.

Works in the Editor, pink or missing in the build

Switch the Play Mode Script to Use Existing Build to reproduce it in the Editor. Pink materials often mean shader variants were stripped because only addressable content used them.

“Attempting to use an invalid operation handle”

The handle was already released, often twice. Release each handle exactly once, and check handle.IsValid() before releasing in OnDestroy.

FAQ

What are Addressables in Unity?

A package for loading assets by address on demand, with reference-counted memory management and optional remote hosting. It’s built on asset bundles but handles their dependencies for you.

Addressables vs Resources: which should I use?

Addressables for anything beyond a prototype. Resources ships everything in the folder, slows startup and can’t host content remotely.

Do I need to release Addressables?

Yes. Call Addressables.Release on every handle you load, and ReleaseInstance on objects created with InstantiateAsync. Otherwise assets stay in memory.

Do Addressables work in WebGL?

Yes, and they’re especially useful there because they let the first download stay small. Remote content must be served with correct CORS headers.

Do addressable scenes need to be in the build list?

No. Load them with Addressables.LoadSceneAsync. Only the first scene the game starts in needs to be in the build profile.

Can I update game content without a new app release?

Yes, for remote groups. Use Update a Previous Build with the saved content state file and upload the new bundles. Code changes still need an app update.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *