Diagnose Unused SVG Definitions with Svgo's removeUnusedDefs
Find and remove orphaned <defs> elements in SVGs with Svgo's removeUnusedDefs plugin before they bloat your optimized output.
08 Oct 2026, 11:30 UTC

Recognize the condition
You run Svgo on an SVG, but the optimized file is almost the same size as the original. The output still contains <defs> blocks for gradients, filters, patterns, or clip paths, yet no element inside the document references their IDs. These orphaned definitions often come from design-tool exports, manual edits, or earlier optimization steps that removed the referencing shapes while leaving the definitions behind.
Useful takeaway: Svgo's removeUnusedDefs plugin can detect and drop definitions that nothing in the file references. Run it as a targeted check, not as an unexamined default, because references can live outside the plugin's view.
Cause and diagnostic table
| Observation | Likely cause |
|---|---|
Optimized SVG still contains <defs> with IDs that appear nowhere else in the file |
Definition was added manually or by a tool, then its referencing element was deleted |
| File size barely changes after Svgo runs | Unused definitions remain because removeUnusedDefs was not enabled |
| Gradient or filter disappears after optimization | The definition was referenced by <use>, CSS, an external document, or an animation the plugin did not detect |
Ordered checks
- Open the SVG in a text editor and list every ID inside
<defs>. Search the rest of the document forurl(#id),fill="url(#id)",stroke="url(#id)", orfilter="url(#id)"matches. Any ID with no match is unused within this file. - Run Svgo with only
removeUnusedDefsenabled so you can isolate its effect from other plugins. - Open the original and optimized SVGs in a browser or vector viewer. Confirm gradients, filters, masks, and
<use>references still render as expected. - Compare file sizes. A meaningful reduction supports the finding; a tiny change may mean the unused definitions were already small or absent.
Example: unreferenced gradient
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<defs>
<linearGradient id="unused-gradient">
<stop offset="0%" stop-color="#ff0000"/>
<stop offset="100%" stop-color="#0000ff"/>
</linearGradient>
</defs>
<rect width="100" height="100" fill="#cccccc"/>
</svg>
Here unused-gradient is never referenced by fill="url(#unused-gradient)", so removeUnusedDefs is a candidate to remove it. If the rect instead used fill="url(#unused-gradient)", the definition would be kept.
Command example
Run this in a terminal inside the project directory that contains the SVG. You need read permission on the input file and write permission on the output location.
npx svgo input.svg --enable=removeUnusedDefs --output output.svg
Replace input.svg and output.svg with your actual paths. Svgo should exit successfully and write output.svg. Do not assume a specific console message; inspect the output file and the exit code instead.
Risk: if you point output at the original file, Svgo overwrites it. Keep a copy before optimizing.
Configuration example
For Svgo 3.x, you can enable the plugin in a config file instead of on the command line:
// svgo.config.mjs
export default {
plugins: [
{
name: 'removeUnusedDefs',
params: {}
}
]
};
Then run:
npx svgo input.svg --config svgo.config.mjs --output output.svg
Fixes tied to findings
- Definition is truly unreferenced: delete it manually, or let Svgo remove it and re-run to confirm the
<defs>block is gone or smaller. - Definition is referenced by
<use>or an external file: keep the definition. Run Svgo with--disable=removeUnusedDefsfor that file, or exclude the plugin in your config. - Definition is referenced only by CSS or animation: the plugin may not see those references. Either add an inline attribute reference if appropriate, or disable the plugin for that file rather than risking broken rendering.
- SVG breaks after removal: restore from backup and do not use the plugin on that file until the missing reference is identified.
Escalation criteria
- Svgo clearly fails to remove a definition that has zero references in the document.
- Removing definitions breaks gradients, filters, masks, or animations, and you cannot find the missing reference.
- Design-tool metadata inside
<defs>is being stripped along with graphical definitions. - You are on Svgo older than 3.x and suspect references from
<animate>elements are being missed; upgrade Svgo before relying on the plugin.
Limitations
removeUnusedDefs scans a single SVG file. It cannot see references in external HTML, CSS files, or other SVG documents. A definition used only by an external <use href="file.svg#id"> will look unused and may be removed. File size reduction is not guaranteed; small definitions may produce almost no savings.
Practical verification
- Back up the original:
cp input.svg input.svg.bak. - Run Svgo with
removeUnusedDefsenabled. - Open
output.svgand search for the IDs that were in<defs>. If an ID was unreferenced, it should no longer appear. - Render both files side by side in a browser. Visual output should match for referenced features.
- If anything is missing, restore
input.svg.bakand disable the plugin for that file.
Rollback
Because Svgo writes a new file, the operation changes state. Keep input.svg.bak until you confirm the optimized SVG renders correctly. To roll back, copy the backup over the output: cp input.svg.bak output.svg.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.