AI agents (Claude Code, Codex, Cursor, and similar tools) are good at answering questions about a
Unity build when they are pointed at UnityDataTool: the analyze command turns the build output into
a SQLite database that an agent can query directly, and the other commands let it drill into
individual files and objects. This page is the recommended workflow, plus the handful of facts that
are not obvious from --help and tend to cost the most discovery time. It is written so it can be
pasted (or linked) into an agent's context, and it is just as useful for humans writing scripts.
-
Analyze the build output into a database. One build per database (see below).
UnityDataTool analyze /path/to/build -o Analysis.db -
Query the database. Any SQLite client works. The
sqlite3command-line shell is the most convenient; if it is not installed, Python's standard library works without any extra setup:sqlite3 Analysis.db ".mode column" "SELECT * FROM view_breakdown_by_type LIMIT 15;"python -c "import sqlite3; [print(*r) for r in sqlite3.connect('Analysis.db').execute(\"SELECT type, count, pretty_size FROM view_breakdown_by_type LIMIT 15\")]" -
Start from the views, not the raw tables. The database ships with views that join the underlying tables into directly useful shapes.
object_view(one row per object, with resolved type/archive/file names andpretty_size) andview_breakdown_by_type(count and total size per object type) answer most first questions. List everything that is available with:sqlite3 Analysis.db "SELECT name FROM sqlite_master WHERE type = 'view' ORDER BY name;"The full schema is documented in the Analyzer database reference; worked example queries are in Example usage of Analyze.
-
Drill down into specific files and objects. Once a query has identified something interesting, the other commands show the actual content:
dumpprints an object's full serialized properties as text.serialized-fileinspects a SerializedFile's header, object list, and external references.archivelists or extracts the contents of an AssetBundle or other Unity archive.
Two different ids. object_view (and objects) has both an id and an object_id column, and
the two drill-down commands take different ones:
idis a small sequential row number assigned byanalyze, unique across the whole database.find-refs -itakes this one.object_idis the object's serialized local file id (them_PathIDseen in references), a signed 64-bit value that is only unique within its SerializedFile.dump -itakes this one.
One build per database. analyze refuses input where two archives (or two standalone
SerializedFiles) have the same name, because queries would be ambiguous — this happens when a
directory contains several builds, or the same AssetBundles built for multiple targets. Analyze each
build into its own database and query them separately (Comparing Builds
shows patterns for diffing them).
TypeTrees are required. Object contents can only be interpreted when the files contain TypeTree
metadata. AssetBundles include it by default; Player builds do not, so analyzing a Player build
typically reports Files without TypeTrees and those files contribute nothing to the database (a
run where every file is skipped produces a valid but empty database). To analyze Player data, build
with the ForceAlwaysWriteTypeTrees diagnostic switch — see
Player Build Format.
Empty names are normal. Many object types (Transform, GameObject components in general) have no
name; object_view.game_object links components back to their named GameObject.
The refs table records every object-to-object reference found during analysis: object is the
referencing object's id, referenced_object is the referenced object's id, and refs_view
adds the property path and type as strings. Querying it directly answers "what references X":
sqlite3 Analysis.db "SELECT object, property_path FROM refs_view WHERE referenced_object = 140;"
Repeat the query with the returned object ids to walk further up the reference graph. Where such
a walk should stop — the objects that by themselves explain "this is why it is in the build" —
depends on the build type:
- AssetBundles: the
assetbundle_assetstable lists the assets explicitly assigned to each AssetBundle. Reaching one of these explains the inclusion, and an object that is itself listed there belongs in the build even when nothing references it. - Content directory builds:
content_layout_loadable_objects_viewlists the loadable objects — the build's entry points. This requires theContentLayout.jsonin the analyze input; see ContentLayout in the Analyze Database. - Player builds: there is no explicit asset list in the build output. The naming conventions of
the serialized files (
level0,sharedassets0.assets,resources.assets, ...) tell you which scene or shared pool pulled the content in; see Player Build Format.
The find-refs command automates walking these chains, but it is
experimental: it does not yet produce complete or clearly-explained results for all supported build
pipelines (issue #121). Prefer
the direct queries above.
Given the question "what is in this AssetBundle build and does anything look wasteful?", analyze the entire build output into one database:
UnityDataTool analyze /path/to/build -o Analysis.db
Then look at, in order:
-- What is in it, by type
SELECT * FROM view_breakdown_by_type;
-- The biggest individual objects
SELECT object_id, type, name, archive, pretty_size FROM object_view ORDER BY size DESC LIMIT 20;
-- Texture formats, sizes, and Read/Write flags
SELECT name, format, width, height, mip_count, rw_enabled, pretty_size FROM texture_view;
-- Meshes with Read/Write enabled
SELECT name, vertices, rw_enabled, pretty_size FROM mesh_view;
-- Objects that appear more than once (same name/type/size in different files)
SELECT * FROM view_potential_duplicates;Interpretation notes: rw_enabled = 1 on textures and meshes doubles their runtime memory cost and
is only needed when scripts access the data on the CPU. view_potential_duplicates compares
objects across the whole build (this is why the full analysis matters) and is only expected to have
results for AssetBundle builds: rows that span archives usually mean a shared dependency was not
assigned to a common AssetBundle, so it was duplicated into each AssetBundle that needs it. To see
a suspicious object in full, dump it from the file the query reported:
UnityDataTool dump /path/to/build/some.bundle -i <object_id> --stdout
When the question is about a single AssetBundle on its own, it can be analyzed in isolation into a throwaway database (build-wide questions such as duplication still need the full analysis above):
UnityDataTool analyze /path/to/assetbundles -o single.db -p my.bundle
The same per-object queries apply — view_breakdown_by_type for what dominates the AssetBundle, then
object_view ORDER BY size DESC and a dump of the biggest objects to see what makes them large
(e.g. texture dimensions and format, or mesh vertex counts).
When using a chat AI that cannot run commands itself, the same information has to be provided as context. Dump the schema of your database into a text file and attach it before asking for queries:
sqlite3 Analysis.db ".schema" > schema_dump.sql.txt
Note that the produced database's schema shows bare table definitions; the meaning of the columns is documented in the Analyzer database reference, which is also useful context.
| Topic | Description |
|---|---|
| Command-line tool | All commands and their options |
| Analyzer database reference | Tables, views, and their columns |
| Example usage of Analyze | More worked queries |
| Comparing builds | Finding what changed between two builds |
| Overview of Unity Content | SerializedFiles, Archives, and TypeTrees |