Unity rules reference
Every diagnostic PerfLint runs on a Unity project, one page each: what triggers it, what it costs, how to fix it by hand, and what the plugin can fix for you.
Each rule has a stable code (PERF.TEX005, ASSET.DUP001…) — the same one the
editor window, the HTML report, and the CLI print. Scanning is free and runs entirely on your machine;
nothing about your project is uploaded. Pages are being added rule by rule, so this list is a subset of
what a scan reports today.
Performance
Import settings and scene data that cost memory, VRAM, or frame time.
- MAT001 Pink materials after switching to URP: the shader belongs to the other pipeline
A material on a Built-in shader in a URP/HDRP project renders pink and isn't SRP-batched. The reverse — an SRP shader on Built-in — fails the same way.
- MAT003 A material with no shader assigned renders magenta
The shader reference is None or points at an asset that no longer exists — a deleted shader, or one from a package that isn't installed in this project.
- PERF.AUD001 Decompress On Load on a long clip puts the whole decoded clip in memory
Decompress On Load expands the whole clip to PCM in RAM at load. Past a few seconds, Compressed In Memory is almost always the better trade.
- PERF.AUD003 PCM audio is the largest format on disk and in memory
Compression Format: PCM is the largest option on disk and in memory. Vorbis is the sane default; ADPCM is the middle ground for short, frequent SFX.
- PERF.LOG001 Debug.Log calls still cost time in a release build
Debug.Log isn't stripped from release builds, and the string is built whether or not anyone reads it. [Conditional] is how you actually remove the calls.
- PERF.MSH001 Read/Write Enabled on a model keeps a duplicate copy of its mesh data
Read/Write Enabled on a model keeps mesh data in CPU memory as well as GPU memory. Unless something modifies the mesh at runtime, that's double memory.
- PERF.SBATCH001 Static Batching pays for draw calls with Combined Mesh memory
Static Batching bakes a merged copy of every batched renderer's geometry: a real CPU win and a real memory bill, and the build-size half is easy to miss.
- PERF.TEX001 Read/Write Enabled keeps a second copy of every texture in RAM
Read/Write Enabled keeps a full CPU-side copy alongside the GPU one, doubling a texture's memory. When you need it, and how to find the ones that don't.
- PERF.TEX002 An uncompressed texture costs several times the VRAM of a compressed one
Compression: None ships raw RGBA — several times the memory and build size of a block-compressed equivalent. How to find them and what to switch to.
- PERF.TEX005 Compression was requested, but the texture imported uncompressed anyway
You set Compressed, Unity imported RGBA32. ETC2 needs dimensions divisible by 4 and PVRTC square power-of-two — miss those and the importer falls back silently.
- MAT002 Enable GPU Instancing drops a material out of the SRP Batcher
Under URP or HDRP, Enable GPU Instancing takes the material off the SRP Batcher path. For most scenes that's a net loss — the opposite of the intent.
- MAT004 GPU Instancing does nothing on renderers that are already static-batched
Static Batching takes priority over GPU Instancing, so ticking Enable GPU Instancing everywhere is inert on static geometry — and worse than inert under an SRP.
- MAT005 GPU Instancing on a skinned-mesh material can never take effect
SkinnedMeshRenderers are drawn individually, so instancing a material only skinned meshes use does nothing — and under an SRP it costs you the SRP Batcher too.
- PERF.AUD002 Background music that isn't set to Streaming stays resident in memory
A clip over half a minute — music, ambience, long VO — belongs on Streaming, where Unity keeps a small buffer instead of the whole thing in memory.
- PERF.MSH002 Mesh Compression is off, which is the default and not always the right one
Mesh Compression quantizes vertex data at import to shrink the build. It's lossy, so it's off by default — but on most props, Low is invisible.
- PERF.TEX003 4K and larger textures, and whether you need them that big
A 4096×4096 texture costs 16× the memory of a 1024. Max Size caps it per platform at import without touching the source art — here's how to decide where.
- PERF.TEX004 Mipmaps on a UI sprite are ~33% memory you never sample
UI sprites are drawn at a fixed screen scale, so their mip chain is never sampled — but it still costs about a third of the texture's memory.
- PERF.TEXSTR001 Texture Streaming is off while a large pool of scene textures qualifies for it
Mipmap streaming loads only the mip levels the cameras need. With it off and a large eligible pool in the scene, that memory is resident for no reason.
- PERF.TEXSTR002 Stream Mip Maps is set on textures, but Texture Streaming is off
Mipmap streaming needs both halves: the per-texture flag and the Quality Settings switch. With the switch off, the flags do nothing at all.
- SHDR001 A shader with a huge keyword space costs import and build-compile time
Unity's 'variants total' is the full keyword space, not what ships — but it's still the number that predicts shader import and build-compile time.
Assets
Build size: duplicated, unreferenced, and badly packed content.
- ASSET.AADUP001 An asset referenced by two Addressables groups gets packed into both
Implicit dependencies are duplicated per group. Unity's Analyze rule finds them; the work is deciding which ones matter and extracting them safely.
- ASSET.ABDUP001 A shared asset with no bundle assignment is copied into every bundle that uses it
Classic AssetBundles copy an unassigned shared asset into every bundle that references it — the same waste as Addressables, with no Analyze window to see it.
- ASSET.DUP001 Byte-for-byte identical asset files, shipping once each
The same texture imported into three folders is three GUIDs and three copies in the build. Finding them is a hash; fixing them means redirecting refs first.
- ASSET.UNREF001 Assets nothing in the build references
An asset no build scene, Resources folder, project setting or bundle assignment can reach is probably dead weight — 'probably' being the careful word.
Migration
Deprecated APIs, package incompatibilities, and upgrade blockers.
- SHDR004 Everything went magenta after the upgrade: the shader no longer compiles
Shaders written for an older Unity break on include paths and macros after an upgrade, and every material using them renders magenta. Unity logs it at import.
- MIG.FindObjectOfType FindObjectOfType is deprecated in Unity 2023.1 and Unity 6
It isn't a straight rename: FindAnyObjectByType and FindFirstObjectByType differ on whether order is guaranteed, and the faster one fits most call sites.
- MIG.LegacyInputApi UnityEngine.Input still called while the backend is New Input System only
Under 'Input System Package (New)', every old UnityEngine.Input call throws InvalidOperationException at runtime. It compiles fine, so nothing warns you first.
- MIG.PackageUnityIncompat An installed package requires a newer Unity than the editor you're running
The package's own manifest declares a minimum Unity version above your editor's. That's not a heuristic — it's the package telling you it isn't supported here.
Project Settings
Player/Editor settings that leave build size or CPU on the table.
- PROJ010 WebGL Compression Format is Disabled, so the whole build downloads uncompressed
For a web build, download size is load time. Brotli cuts the .wasm and .data payload substantially, and Disabled is the one setting here that's a pure loss.
- PROJ002 Managed Stripping is disabled under IL2CPP
IL2CPP compiles unused managed code into your build. Stripping removes it; the reason it's ever off is reflection, and link.xml is the right fix for that.
Want the whole list applied to your own project instead of read one page at a time? Install the free scanner — it reports every rule above, with the exact files, and no upload. For measured before/after cases, see the blog.