Quick answer: Run Build → Update a Previous Build with a fresh content_state.bin, set Disable Catalog Update on Startup = false, and upload both the new catalog and bundles with proper cache headers. Use ClearDependencyCacheAsync for forced refresh.
You ship a content update with a new sword sprite. Three days later, players still see the old sprite. The CDN has the new files. The catalog hash changed. But the client keeps loading from its local cache and never fetches the update.
The Caching Layers
Addressables has multiple levels:
- Catalog — lists every addressable and where to find it. Cached by the runtime.
- Bundles — binary blobs containing assets. Cached on disk by Unity’s caching system.
- Asset references — in-process handles to loaded assets.
For a content update to take effect, the runtime must (a) realize the catalog changed and (b) re-download the affected bundles. Both need to happen for new content to reach the player.
Step 1: Catalog Update on Startup
Open Project Settings → Addressables. Find Disable Catalog Update on Startup — this should be off for live games. With it on, the client uses the catalog baked into the binary forever, regardless of what’s on the CDN.
Alternatively, trigger a manual check at the title screen:
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
async Task CheckForContentUpdate() {
var handle = Addressables.CheckForCatalogUpdates();
List<string> updates = await handle.Task;
if (updates.Count > 0) {
await Addressables.UpdateCatalogs(updates).Task;
Debug.Log($"Updated {updates.Count} catalog(s)");
}
}
Call this once at startup. Returns the list of changed catalogs and downloads them.
Step 2: Force-Clear Specific Bundles
If a catalog says “bundle X is at version 2” but the client cached version 1 under a non-hash-versioned URL, it may keep using the old bundle. Clear:
await Addressables.ClearDependencyCacheAsync("swords", true).Task;
The string is the addressable label or key. Passing true also unloads loaded bundles before clearing. Next load forces a fresh download.
Step 3: Build Pipeline Sanity
Use Window → Asset Management → Addressables → Build → Update a Previous Build (not New Build) for incremental updates. This pipeline:
- Reuses the previous
addressables_content_state.bin - Detects which bundles changed
- Builds only changed bundles
- Produces a new catalog whose hash differs from the old one
Upload both the new catalog and the new bundles to your CDN. Critically, set CDN cache headers like Cache-Control: max-age=3600 on bundle files but Cache-Control: no-cache on the catalog JSON — the catalog must always be fresh.
Step 4: Diagnose with Logs
Enable Addressables runtime logging:
Addressables.ResourceManager.RegisterDiagnosticCallback(diag =>
Debug.Log($"{diag.EventType} {diag.Context}"));
Watch for “CacheHit” vs “Download”. A run that should fetch new content showing CacheHit on the affected bundle means the cache isn’t being invalidated.
Verifying
Deploy a known content change (e.g., color of one icon). Have a tester open the app. Inspect Unity’s cache folder (Library/Cache or device-specific path). The bundle hash should differ from yesterday’s. The icon should reflect the new content within seconds of app launch.
“Catalog drives discovery; cache control drives delivery. Both must be correct, or your content update silently doesn’t ship.”
Wire up a debug menu that lists cached bundle hashes — saves QA hours when testing live updates.