How to delete unused <defs> and dead code from svg files
- Step 1Open the purger and confirm you are on Pro — The Unused Defs Purger is a Pro-tier tool. On the free plan you see an upgrade overlay instead of the upload area — the DOM traversal is gated behind Pro. Signed in on Pro, the per-job size limit is 50 MB (free-equivalent jobs cap at 5 MB on other SVG tools).
- Step 2Drop the SVG or paste the source — Drag one
.svgfile onto the dashed area, click to browse, or paste the raw<svg>…</svg>markup into the source box. This is a single-file tool — it processes one SVG per run (the sprite builder is the only multi-file SVG tool). Pasted markup is validated as parseable SVG XML before processing. - Step 3Run the purge — Click Process SVG. The tool parses the file with
DOMParser, gathers everydefs > *element that has anid, scans the document for references, and removes the ids that are never referenced. There are no options to set — the behaviour is fixed. - Step 4Read the Defs removed metric — The result panel shows
Defs removed: Nalongside Original and Output byte sizes and a Saved percentage. IfDefs removedis0, every def in your file was referenced (or your<defs>children had noidto match on) — nothing was changed. - Step 5Eyeball the inline preview — The cleaned SVG renders live in the preview pane. Because only unreferenced definitions are removed, the visible artwork should be pixel-identical. If anything disappeared, a reference lived somewhere the regex cannot see — see the edge-cases section.
- Step 6Copy or download the purged SVG — Use Copy to clipboard for paste-into-code, or Download to save
<name>-purged.svg. For maximum size savings, chain into the Pro-Minifier (whitespace/comments) and Precision Tuner (coordinate decimals) afterwards.
What the purger removes vs. keeps
The rule is mechanical: a direct id-bearing child of <defs> is removed only when its id appears in no url(#id) and no (xlink:)?href="#id" anywhere in the serialized document.
| Definition type | Removed when… | Kept when… |
|---|---|---|
<linearGradient id> / <radialGradient id> | No fill="url(#id)", stroke="url(#id)", or xlink:href="#id" (gradient chaining) anywhere in the file | Any element — or another gradient via href — references the id |
<clipPath id> | No clip-path="url(#id)" references it | A shape or group carries clip-path="url(#id)" |
<filter id> | No filter="url(#id)" references it | A shape carries filter="url(#id)" |
<mask id> | No mask="url(#id)" references it | A shape carries mask="url(#id)" |
<marker id> | No marker-start/-mid/-end="url(#id)" references it | A path carries any marker-*="url(#id)" |
<symbol id> / <pattern id> | No <use href="#id"> / fill="url(#id)" references it | A <use> or fill points at the id |
<defs> child without an id | Never — the tool only evaluates id-bearing children | Always preserved (it can't be matched, so it can't be flagged unused) |
Empty <defs> wrapper | After purging, if it has zero children left | If at least one child survives |
Where this tool sits among the SVG cleanup tools
The purger only touches <defs>. For other dead weight, reach for the sibling tool listed.
| You want to remove… | Right tool | Why |
|---|---|---|
| Unreferenced gradients / clip-paths / symbols | Unused Defs Purger (this tool) | The only tool that does id-reference analysis on <defs> |
| Comments, whitespace, redundant namespaces | SVG Pro-Minifier | Strips non-visual markup; does not analyse defs references |
Editor fingerprints, <title>/<desc>, <metadata> | SVG Metadata Scrubber | Targets Illustrator/Figma/Inkscape signature data |
| Excess decimal places on coordinates | SVG Precision Tuner | Rounds path numbers; orthogonal to defs cleanup |
| Redundant path nodes on polylines | SVG Path Simplifier | RDP node reduction on M/L-only paths |
Cookbook
Real <defs> blocks before and after a purge. Ids and colours are illustrative; the removal logic shown is exactly what the tool runs.
Figma export with three orphan variant gradients
Figma pre-generated gradients for hover/active/disabled variants. You exported only the default frame, so two of the three gradients are referenced by nothing. The purger removes them and reports Defs removed: 2.
Before: <defs> <linearGradient id="grad-default">…</linearGradient> <linearGradient id="grad-hover">…</linearGradient> <linearGradient id="grad-active">…</linearGradient> </defs> <rect fill="url(#grad-default)" .../> After (Defs removed: 2): <defs> <linearGradient id="grad-default">…</linearGradient> </defs> <rect fill="url(#grad-default)" .../>
Leftover clipPath after a boolean edit
Illustrator left a clip-path behind when you flattened a mask. No element carries clip-path="url(#clip-old)", so it goes.
Before: <defs> <clipPath id="clip-old"><circle r="20"/></clipPath> </defs> <path d="…" fill="#222"/> After (Defs removed: 1, empty <defs> also deleted): <path d="…" fill="#222"/>
Gradient chained via xlink:href is preserved
grad-base defines the stops; grad-skin reuses them with xlink:href="#grad-base" and only overrides the angle. The rect uses grad-skin. Because the href reference is matched, grad-base survives even though no shape points at it directly.
<defs> <linearGradient id="grad-base"><stop offset="0" stop-color="#06f"/></linearGradient> <linearGradient id="grad-skin" xlink:href="#grad-base" gradientTransform="rotate(45)"/> </defs> <rect fill="url(#grad-skin)" .../> Result: Defs removed: 0 — both kept (grad-base matched by href).
Def-to-def reference within an unused def is NOT cascaded
clip-unused is referenced by nothing, so it is removed. Its body contains url(#grad-only) — and because the reference scan reads the whole file BEFORE removal, grad-only is seen as referenced and kept, even though its only user just got deleted. The tool is single-pass; run it twice to collect the now-orphaned gradient.
<defs> <clipPath id="clip-unused"><rect fill="url(#grad-only)"/></clipPath> <linearGradient id="grad-only">…</linearGradient> </defs> <!-- nothing references #clip-unused --> Pass 1: Defs removed: 1 (clip-unused). grad-only KEPT. Pass 2: Defs removed: 1 (grad-only now truly orphaned).
Purge-then-minify pipeline for a heavy icon
A single decorative icon shipped with a filter library it never uses. Purge the dead filters, then minify, then tune precision for the smallest result.
Step 1 Unused Defs Purger → icon-purged.svg (Defs removed: 4) Step 2 SVG Pro-Minifier → comments/whitespace stripped Step 3 SVG Precision Tuner → coordinates rounded to 2 dp Net: dead <defs> gone, then byte-level minification on the smaller markup — defs removal first means fewer bytes to minify.
Edge cases and what actually happens
Free-tier user opens the tool
Pro requiredThe purger is a Pro-tier tool. Free-plan visitors see an upgrade overlay where the upload area would be — there is no free run. Upgrade to Pro (or run it inside the desktop runner on a Pro plan) to process files. Pro raises the per-file ceiling to 50 MB.
A def is referenced only from an external CSS file
Removed in errorThe tool analyses the SVG document alone. If a stylesheet outside the file does .box { fill: url(#brand-grad); }, that reference is invisible to the scan and brand-grad will be removed as unused. Inline the reference into the SVG, or keep the gradient in a file you do not run through the purger.
A def is referenced from JavaScript at runtime
Removed in errorIds selected with getElementById('#fx') or applied dynamically (e.g. JS sets filter: url(#fx) on hover) are not present as static url(#id) / href="#id" text in the markup, so the purger treats them as unused and strips them. There is no preserve-id box — keep dynamically-referenced defs out of the purge or re-add them afterwards.
A `<defs>` child has no `id` attribute
PreservedThe tool only collects defs > * elements that carry an id. A definition with no id is never a candidate for removal, so it is always kept — even if it is genuinely dead. This is conservative by design: an id-less def cannot be matched against the reference set.
Reference uses a CSS color directly, not url()
Removed in errorThe reference regex requires the url(#…) form. A non-standard or hand-written fill="#grad" (without url()) does not match, so the gradient it points at is seen as unused. Standard SVG paint references always use url(#id), so well-formed files are safe — but hand-edited markup that drops url() will lose the def.
Transitive dead defs after one pass
By designBecause the reference scan runs once over the original markup, a gradient whose only consumer was itself an unused clip-path stays in the file on pass one (the scan saw url(#grad) inside the doomed clip-path before it was removed). Run the purger a second time to sweep up defs that became orphans only after the first removal.
Symbol used by <use> on a different page
Watch closelyIf a <symbol> has no <use href="#id"> inside this file but is referenced from another HTML page or sprite consumer, the purger will mark it unused and remove it — it cannot see cross-document usage. For shared sprites, keep the master sprite intact and only purge per-icon working copies. The SVG Sprite Builder is the right tool for assembling sprites.
Pasted markup that is not valid SVG XML
Invalid inputPasted source is validated first: it must parse as XML with a root <svg> element and no parser error. Truncated markup, an HTML fragment, or a stray ampersand fails validation with an "Invalid SVG" message and nothing is processed. Fix the markup or upload the original .svg file.
File exceeds the tier size limit
413 rejectedA file larger than the Pro 50 MB per-job ceiling is blocked before processing with a tier-limit message. SVGs are text, so 50 MB is enormous for vector art — hitting it usually means embedded base64 raster data, which the purger does not touch (and which the SVG Compression Estimator can quantify).
Frequently asked questions
How does the tool decide a def is unused?
It collects every direct child of <defs> that has an id, then scans the full serialized SVG for url(#id) and (xlink:)?href="#id" patterns. Any id not found in that scan is removed. It is a literal text match against the whole document, including the contents of other defs.
Can it remove a def that is referenced in an external CSS file?
Yes — and that is a false positive to watch for. The tool only reads the SVG document. A reference living in a separate .css file (fill: url(#grad)) is invisible to it, so the def will be removed. Inline the style into the SVG before purging, or do not purge files whose defs are styled externally.
Is there a preserve-id list to protect specific definitions?
No. The tool has no options at all — no preserve box, no checklist, no settings panel. Removal is fully automatic based on the reference scan. If you need to keep a def that has no static reference (e.g. it is used by JavaScript), keep that file out of the purger or re-add the def afterwards.
What tier is required?
Pro. Free-plan users see an upgrade overlay instead of the tool. On Pro the per-file limit is 50 MB.
Does it work on SVG sprites?
It runs, but be careful. A <symbol> with no <use href="#id"> inside the same file is treated as unused and removed — even if other pages reference it. The tool cannot see cross-document usage. Keep the canonical sprite intact; only purge isolated copies. Build sprites with the SVG Sprite Builder.
Will purging change how my SVG looks?
It should not. Only definitions that nothing references are removed, so painted output is unchanged. If something visibly disappears, a reference existed somewhere the scan can't reach (external CSS, JavaScript, or a non-url() paint value).
Does it handle gradients that reference other gradients via xlink:href?
Yes. Gradient chaining (<linearGradient xlink:href="#base">) is matched by the (xlink:)?href="#id" part of the scan, so a base gradient reused only through href is kept even though no shape points at it directly.
Why did Defs removed come back as 0?
Either every def in your file is genuinely referenced, or your <defs> children have no id attributes (id-less children are never candidates for removal). Check that the defs you expected to drop actually carry ids and are direct children of <defs>.
Does it strip comments, whitespace, or metadata too?
No. It only removes unreferenced <defs> children and any empty <defs> wrapper. For comments and whitespace use the SVG Pro-Minifier; for editor fingerprints and <title>/<desc> use the SVG Metadata Scrubber.
Is my file uploaded anywhere?
No. Processing runs in your browser via the DOM. The result panel shows a 0 bytes uploaded badge to confirm. On a Pro plan with the local desktop runner installed, the job can run in the runner instead — still on your own machine.
Can I run it on a whole folder of icons at once?
Not in this single-file web tool — it processes one SVG per run. For batch cleanup, the desktop runner exposes the same svg-unused-defs-purger operation per file; see the automation guide. There is no public cloud API for this tool because it needs a DOM to run.
What is the output filename?
<original-stem>-purged.svg. So logo.svg downloads as logo-purged.svg.
Privacy first
Every JAD SVG tool runs entirely in your browser using the DOM API and Canvas. Your SVG files never leave your device — verified by zero outbound network requests during processing.