Unused Asset Finder
Lists assets under Assets/ that look unused. Never deletes files. Optional quarantine moves them with AssetDatabase.MoveAsset to Assets/AnvilReports/quarantine/.
Editor-only. Unity 2021.3+. Lives in Anvil.Editor (includePlatforms: Editor). No extra packages.
What "unused" means
Default (reachable-from-roots OFF): an unused asset is one whose GUID is never referenced by another asset. Own .meta does not count as a usage. Two assets that only reference each other are not reported.
Reachable from roots ON: build scenes plus anything under Resources/, StreamingAssets/, Editor/, or Plugins/, and .asmdef files, are roots. Anything not reachable from those roots via AssetDatabase.GetDependencies (direct edges, BFS) is unused. Mutual-only islands are reported in this mode (A↔B with no path from a root).
Always-used rules still apply in both modes (those assets are never listed).
Editor window
ArTchie / Anvil / Unused Asset Finder
| Control | What it does |
|---|---|
| Include / Exclude | Comma-separated assetPath substrings. Empty include = all. Exclude wins. Applied on Scan and as a live row filter. |
| Type filter | Substring on Unity type name (Texture2D, MonoScript, …). Empty = all types. Applied on Scan and live. |
| Ignore scripts (.cs) | Default ON. Hides .cs so code-only scripts do not flood the list. Toggle then Scan to include them. |
| Reachable from roots | Default OFF. Scan again after toggling. |
| Sort by size (else path) | Display sort. Size is largest-first using on-disk file length. |
| Scan | Builds a reverse GUID map from YAML/text assets and .meta files under Assets/ (skips Packages/, Library/, and Assets/AnvilReports/quarantine). |
| Copy JSON | Puts the last scan's report JSON on the clipboard. |
| Write report | Writes <project>/AnvilReports/unused-assets.json (creates the folder if needed). |
| Move to AnvilReports/quarantine (Undo-ish: use AssetDatabase.MoveAsset) | Moves checked unused rows, or all currently filtered rows if none are checked. Skips if the destination already exists. Does not delete. Then rescans. |
| Ping / Select | AssetDatabase.LoadMainAssetAtPath then EditorGUIUtility.PingObject (Select also sets Selection.activeObject). |
Each row is: assetPath, guid, Unity type name, and bytes (file length).
Batchmode (CI)
Unity -batchmode -nographics -quit -projectPath <proj> -executeMethod Anvil.UnusedAssetFinder.RunBatch -anvil-out <file.json> -anvil-fail
| Arg | Meaning |
|---|---|
-anvil-out <file.json> |
Output path. Default: <project>/AnvilReports/unused-assets.json |
-anvil-fail |
Exit code 1 if any unused assets were found; otherwise 0 |
-anvil-include <substr> |
Repeatable. Keep only unused rows whose assetPath contains at least one include. |
-anvil-exclude <substr> |
Repeatable. Drop unused rows whose assetPath contains any exclude. |
-anvil-type Texture2D |
Optional. Keep rows whose type contains this substring. |
-anvil-include-scripts |
Include .cs files. Default is to exclude them. |
-anvil-reachable-roots |
Turn reachable-from-roots mode ON. Default is OFF (never-referenced). |
-anvil-quarantine |
After the scan, AssetDatabase.MoveAsset matching unused rows to Assets/AnvilReports/quarantine/, then write JSON with "quarantined". Without this flag, batch never moves files. |
RunBatch only calls EditorApplication.Exit when Application.isBatchMode is true. It logs count=, assetsScanned=, quarantined=, and the output path.
Also accepts -anvil-out=file.json, -anvil-include=substr, -anvil-exclude=substr, and -anvil-type=Texture2D.
JSON
{
"tool": "UnusedAssetFinder",
"generatedUtc": "2026-08-18T02:00:00Z",
"count": 1,
"assetsScanned": 42,
"quarantined": 0,
"items": [
{
"assetPath": "Assets/Art/orphan.png",
"guid": "deadbeefdeadbeefdeadbeefdeadbeef",
"type": "Texture2D",
"bytes": 12345
}
]
}
bytes is on-disk file length. assetsScanned is how many Assets/ files were considered (folders, Packages, Library, and quarantine excluded). quarantined is how many files MoveAsset actually moved (0 unless the window button or -anvil-quarantine ran). Batch JSON items still list the unused paths from the scan (pre-move).
Always treated as used (never reported)
- Anything under an
Editor,Resources,StreamingAssets,Plugins,Gizmos, orEditor Default Resourcesfolder - Scenes listed in
EditorBuildSettings.scenes - Currently open / active editor scenes when that list is readable
.asmdefassets- Files named like a README (
README,Readme.md,read_me, …) - Folders themselves (not listed as unused)
Quarantine
- Destination:
Assets/AnvilReports/quarantine/<path under Assets/>(for exampleAssets/Art/orphan.png→Assets/AnvilReports/quarantine/Art/orphan.png). - Uses
AssetDatabase.MoveAsset(Unity may offer Undo in the editor). Never deletes. - Skips a file if the destination already exists (no overwrite, no timestamp rename).
- Refreshes
AssetDatabaseafter moves. - Quarantined files are skipped on later scans so they do not flood the list.
Notes
- Default reference map:
guid:tokens in YAML/text (.unity,.prefab,.asset,.mat,.controller,.anim,.preset,.vfx,.shadergraph,.asmref, and other text assets) plus every.meta. AlsoAssetDatabase.GetDependencies(direct) so binary-serialized assets are not missed. - C#
using/ type references are not GUID references. Ignore-scripts (default ON) keeps those from filling the report; pass-anvil-include-scriptsor uncheck the box and Scan if you want them. - Addressables, AssetBundles, and Resources-style loads by string are not modeled beyond the always-used folders / root folders above.
- Empty projects and a missing
AnvilReportsfolder are fine. - Does not touch runtime player code. Whole file is
#if UNITY_EDITOR.
Source in the box: Assets/ArTchie Studios/ArTchie-Suite/com.artchie.anvil/Documentation/UnusedAssetFinder.md