Tutorial · images · Published 2026-08-16 · 3 min read
Optimising SVGs for the web
SVG optimisation: remove metadata and precision noise, purge hidden layers and unused defs, minify the markup and serve it compressed.
An SVG is text, but text fat
SVGs reach the browser as markup, so their weight is the number of digits, nodes, and defs in the file. A 60 KB SVG is usually not a complex drawing; it is a 10 KB drawing with 50 KB of editor metadata, precision values like 0.00054321, unneeded groups, and duplicate gradients. An optimiser can often take 300 KB to 12 KB without visual change.
The two levers, in order of value:
- File cleanup: metadata, comments, editor namespaces, unused defs, groups that change nothing.
- Path simplification: reduce the number of path segments, the decimal precision, and the
transformandstylerepeat that pad every command.
The cleanup pass
For a single icon or logo:
npm install -g svgo
svgo --input icon--full.svg --output icon.svg
SVGO is the standard open-source minimiser for the format: it deletes comments and hidden layers, <metadata>, and the sodipodi/inkscape namespace, merges groups, and shortens path d commands. On any setup, run SVGO from a source control workflow: commit the original and re-run the tool as a build step, and never hand-edit the minified line by hand (a source-of-truth pattern the image guide applies to all formats).
Precision matters: the file is smaller when paths keep 2-3 decimals. SVGO's --precision 3 handles that. For logos, keep the <title> for accessibility but strip sodipodi and metadata.
When a renderer resists
Two failure shapes give the "optimiser broke it" finger:
- An image that uses CSS classes the optimiser renamed (for example, a sprite shared by several consumers): disable
cleanupIdsor encode the IDs used inline. - A file with
stylevsclassinterplay: most of the time keepcollapseGroups, but check the filter plugins (thefeGaussianBlurandfilterwhitelist). If a filter disappears, re-enable the matching plugin id in the SVGO config.
A good rule: keep one authoritative original with the editor (.ai or .svg source), run the optimiser as a build step, and diff-verify that the output renders on both light and dark backgrounds (the parts that break visibility, not just load).
Serve it compressed
Even a clean SVG text-compresses again on the wire: gzip alone typically saves another 60% on a minified file, and Brotli more. The CDN static assets article covers why the edge cache handles the compressed transfer. Two delivery nitpicks for SVGs:
- Serve with
Content-Type: image/svg+xmland aVary: Accept-Encoding; a wrong MIME blocks the render in some browsers. - For an SVG with a brand font purposefully missing, an inlined fallback: some browsers do not rasterise
system-uiif the font is not loaded, so add afont-familyfallback chain inside the SVG or pick a webfont-less result.
The icon-set pattern
For icon sets, inline the whole set once and reference by symbol instead of per-icon XML. That saves a request per icon and lets one hover style rule repaint the set. The favicon article covers the single-file favicon case; the SVG vs PNG article covers when a raster is still the cheaper route.
Measure
ls -la icon.svg and a roundtrip curl -I downloaded size. A clean logo in the 1-5 KB range is normal; a 500 KB "logo" is optimisation debt. The image optimisation guide applies the same measure-shrink-serve loop to photographic formats, and the CDN delivery section finishes the serving side.