# 6. Content Builds Updates and CI
Part of [[Addressables]]. Previous: [[5. Scenes Catalogs and Remote Content]]. Next: [[7. Addressables Pitfalls and Quest]].
> [!note] Verification status
> Content builds and the update/Prevent Updates workflow are official Addressables features (the 4.x changelog still refers to the content-update restrictions window and Prevent Updates groups, so the concept has continued past 2.9). **Exact Groups-window button labels** can differ between 2.9 and 4.1 and were not click-verified. The CI hook is a command-line `-executeMethod` you add next to [[2. Command Line Builds and a Build Script]]. **Not run in Unity or on GitHub Actions.**
## 6.1 Two builds
A player build (Build Profile) produces the executable. An Addressables **content build** produces the bundles plus the catalog in the local / remote build paths from the active Addressables profile.
Order that works:
1. Set the Addressables profile (`Local` or `RemoteDev`).
2. Run a **New Build > Default Build Script** from the Addressables Groups / Build menu (wording varies by version).
3. Then build the player (or include the content-build call in the same Editor script, still on one platform — [[2. Command Line Builds and a Build Script]]).
If you skip (2), a Player using "existing build" / packed-mode data will have nothing to load. CI that only calls `BuildPipeline.BuildPlayer` will ship an empty catalog.
Output of a local profile usually lands under `Library` / `ServerData` / `StreamingAssets` depending on how the profile is set. Whatever is supposed to ship *inside* the player must be in a path the player includes (typically StreamingAssets). Whatever is remote must be **uploaded** to the host (CCD or otherwise) as a second CI step.
## 6.2 Content updates (patches without a new player)
The "content update" workflow is how you ship a new hat without resubmitting the whole store build:
1. Some groups are marked so they **should not change** in a patch (binaries already inside the player, or a "Prevent Updates" style constraint — the exact schema name in your version is the one to use).
2. You run the **content update** build, which compares against a previous content state and emits new bundles / a new catalog for what *did* change.
3. The player downloads the new catalog, then only the changed bundles.
This is powerful and easy to misuse. Assets in a "static" group that *do* change get pulled into an update group (folder entries have had several official fixes here in 4.x). For a class, demonstrate it once with a single remote texture. For a shipped Quest title, practice on a staging catalog before you point the live load path at it.
If you do not need patches, skip this and do a full content build with every player build. That is the honest path for most student projects.
## 6.3 Hooking CI
Add a static method that you call **before** `BuildPipeline.BuildPlayer`, in the same Editor process, already started with the right `-activeBuildProfile` / platform:
```csharp
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEngine;
public static class CiAddressables
{
public static void BuildContent()
{
AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null)
{
Debug.LogError("CiAddressables: no AddressableAssetSettings in the project.");
EditorApplication.Exit(1);
return;
}
AddressableAssetSettings.BuildPlayerContent();
Debug.Log("CiAddressables: BuildPlayerContent finished.");
}
}
#endif
```
`AddressableAssetSettings.BuildPlayerContent()` is the common Editor API for a default content build. **Confirm the method and any return/result type against your installed package** (2.9 vs 4.1 may add overloads or a result struct). If the API reports failure in your version, exit non-zero.
A cautious CI sequence:
1. `-executeMethod` content build (same platform as the player)
2. `-executeMethod` or `-build` the player
3. If remote: upload the remote build folder to the host (separate step; credentials in secrets)
Do not start a second Unity process in between and expect the first process's output to be optional — the player needs the files from step 1.
## 6.4 Localization and other packages
[[Localization]] stores tables as Addressable assets. A content build is also a localization build. If a locale is missing in the Player but present in the Editor, the usual cause is a group excluded from the content build or a Play Mode Script that hid the problem.
## Official docs
- Addressables 2.9.1 manual index: https://docs.unity3d.com/Packages/
[email protected]/manual/index.html
- [[Build Automation and CI]]