Safely Deleting Cruft from Long-Lived Unity Projects

Intended Audience: Intermediate to Advanced Unity Developers

Estimated Reading Time: 8 minutes

The Problem

Unity projects accumulate cruft. Prototype assets, abandoned shader experiments, renamed files leaving orphans, test textures that outlived their tests. Over months and years, a project's Assets folder becomes an archaeological dig site.

The fear of deleting anything is rational. Unity references assets by 32-character GUIDs, not filenames. A material references a texture by GUID. A prefab references a script by GUID. A scene references everything by GUID. Delete the wrong file and you get pink materials, missing scripts, or broken prefabs that only surface at runtime.

Unity's editor offers no help. There is no "find unused assets" feature. When something goes missing, Unity shows you a cryptic GUID and "Missing" with no context. The asset is gone, the meta file is gone, and Unity has no memory of what it was.

This post describes improvements I made to a static analysis tool that scans Unity projects for broken and unused asset references, giving developers confidence to clean house.

The Tool

MWDRefTool is a standalone .NET console application that runs outside Unity. It scans a Unity project's Assets folder, extracts GUIDs from meta files (providers), parses scenes/prefabs/materials for GUID references (consumers), and reports:

  1. Broken references - assets that reference GUIDs that don't exist
  2. Unused assets - assets that exist but nothing references them

The tool maintains a persistent SeenAssetGuids.txt file that remembers every GUID it has ever seen. When a broken reference appears, the tool can report "last seen at: Assets/Old/DeletedTexture.png" instead of just showing an orphaned GUID.

What We Fixed Today

Starting with a project showing 368 potentially unused assets and several broken references, we made incremental improvements to reduce false positives and catch real issues.

Materials as Consumers

The original tool scanned .unity, .asset, and .prefab files for GUID references. Materials (.mat files) were tracked as providers (they have GUIDs) but not scanned as consumers.

This was wrong. Materials reference textures and shaders by GUID. A texture used only by a material would incorrectly appear as "unused."

Adding .mat to the consumer list immediately found new broken references: materials still pointing to deleted textures from previous project iterations.

Animation Controllers

Similarly, .controller files (Unity's animation state machines) reference animation clips by GUID. Adding these as consumers correctly identified animation clips as "used" when they were part of an animator.

ShaderGraph JSON Format

Unity's ShaderGraph files use JSON internally, not YAML. The GUID format differs:

YAML (scenes, prefabs, materials):

guid: 59147509cc7dc4d749f8e4611caee58c

JSON (shadergraph):

"guid":"59147509cc7dc4d749f8e4611caee58c"

The tool needed a second regex pattern to catch both formats. Without this, textures referenced only by shadergraphs appeared unused.

Project Settings

Unity's ProjectSettings folder contains files that reference assets: app icons, splash screens, default render pipelines. Adding these as consumers caught references that would otherwise be missed.

Baked Lighting Data

Unity stores baked lightmaps in folders named after their scenes. A scene called Level1.unity has its lighting data in Level1/Lightmap-0_comp_dir.png, Level1/LightingData.asset, etc.

These files have no explicit GUID references pointing to them. Unity's lighting system knows to look in the matching folder. The tool was flagging hundreds of lightmap textures as unused.

The fix: detect files matching Lightmap-*, ReflectionProbe-*, and LightingData.asset patterns and exclude them from the unused report.

The Skybox Case

Six-sided skybox materials reference six textures for the cube faces. In some workflows, Unity generates these face textures as derived assets in the Library folder at import time. They have GUIDs, but they don't exist as files in the Assets folder.

The tool was reporting these as broken references. Technically correct (the GUIDs don't resolve to files we can see), but practically useless. The skybox works fine at runtime.

The solution was adding skybox.mat to the ignored problems list with case-insensitive matching. Any material following the *Skybox.mat naming convention gets a pass on "missing" cubemap face references.

Extension-Based Exclusions

Some file types are inherently "unused" from Unity's GUID perspective but still valuable:

These are now excluded from the unused report via a configurable list.

Folder-Based Exclusions

Some folders have special Unity semantics:

Assets in these folders are excluded from the unused report.

Results

After these improvements:

The remaining 53 "unused" assets are genuinely unused: prototype audio files kept for future use, reference art, abandoned prefabs. A human can now review that list meaningfully instead of drowning in false positives.

The Workflow

With the tool in place, cleaning a Unity project becomes systematic:

  1. Run the tool
  2. Review broken references (these are real problems)
  3. Review unused assets (these are candidates for deletion)
  4. Delete assets you're confident about
  5. Run the tool again to verify no new breaks
  6. Repeat

The SeenAssetGuids.txt file acts as institutional memory. Even if someone deleted an asset months ago, the next time a broken reference surfaces, you get context: "last seen at Assets/Characters/OldHero/Texture.png" tells you more than a naked GUID ever could.

Lessons

Static analysis beats runtime discovery. Finding a pink material during playtesting means stopping, investigating, and context-switching. Finding it in a report before you run the game is faster.

Consumer types multiply. Every Unity file format that can hold GUID references is a potential consumer. The list grows: scenes, prefabs, assets, materials, animation controllers, shadergraphs, timeline assets, and more. If you see false positives, check whether you're missing a consumer type.

Some references are invisible. Baked lighting, generated cubemap faces, and other derived assets exist in Unity's runtime world but not as scannable files. Know these edge cases and handle them explicitly.

Persistent memory matters. The value of tracking "what was this GUID?" increases over time. A fresh scan knows nothing about deleted assets. A year of accumulated history knows everything.

Current State

The tool now handles:

The ignored problems list handles known Unity quirks like URP global settings and graphics settings that reference package assets.

For a multi-year, multi-developer Unity project, this is the difference between "never delete anything" and "delete with confidence."

Back to Home