Work in this order. Each step is cheaper than the one after it.
If the report's two header numbers differ, stripping is not running somewhere. Fix that first: a settings change that recovers hundreds of thousands of variants is worth more than any amount of shader editing. See Always Included Shaders.
Once the numbers converge, the remaining count is real work your project is asking for, and the steps below apply.
URP003 ranks shaders by variant count. The distribution is almost always lopsided - two or three shaders carry most of the total. Changes to anything below them do not move the number.
URP004 lists, per shader, the keyword sets ordered by size, each marked as always compiled or strippable. A set of size 4 divides that shader's count by 4 when removed.
In your own shaders:
#pragma. The cheapest option, when the feature is not used at all.multi_compile to shader_feature. A multi_compile set is compiled in full regardless of
materials. If the keyword is only ever set on the material rather than globally from script,
shader_feature lets stripping narrow it. This is often the single largest change available._local variants. shader_feature_local and multi_compile_local keep the keyword out of
the global keyword space, which has its own 4,294,967,294-keyword project limit, and makes the
intent clear.#pragma skip_variants KEYWORD_A KEYWORD_B. Removes specific keywords from the shader's
variant space without editing the sets that declare them. Useful for pipeline features you never
enable.multi_compile_fragment and multi_compile_vertex restrict a
keyword set to one stage rather than expanding it across both.For shaders you do not own - the pipeline's - editing the source is not an option. Implement
IPreprocessShaders and remove combinations there:
using System.Collections.Generic;
using UnityEditor.Build;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Rendering;
class StripUnusedVariants : IPreprocessShaders
{
public int callbackOrder => 0;
static readonly ShaderKeyword Decals = new ShaderKeyword("_DBUFFER_MRT1");
public void OnProcessShader(Shader shader, ShaderSnippetData snippet,
IList<ShaderCompilerData> data)
{
for (int i = data.Count - 1; i >= 0; i--)
{
if (data[i].shaderKeywordSet.IsEnabled(Decals))
data.RemoveAt(i); // this project does not use decals
}
}
}
Remove only what you are certain of: a variant stripped here that the game needs renders as magenta in the player and not in the editor.
URP also exposes stripping switches on the URP Asset and in the URP Global Settings - decals, post-processing, terrain, screen-space shadows, additional light modes. Turning off a pipeline feature you do not use removes its keywords before any of the above is needed.
Re-run the audit after each change rather than batching them. The report is fast enough to run on every change, and it tells you whether the edit did what you expected before you spend a build on it.