How to Optimize SVG Files with SVGO
This guide is the first step in SVG & Icon Optimization, within Image & Media Optimization. SVGs exported from design tools are written for editability, not delivery. They carry editor metadata, layer names as IDs, hidden layers, unused definitions, default attribute values spelled out in full, nested groups that do nothing, and path coordinates with far more decimal places than any screen can show. None of it changes what users see; all of it costs bytes in HTML (for inline SVG) or in requests (for files).
SVGO is the standard tool for removing that bloat. Its default preset applies dozens of safe transformations — removing metadata and comments, collapsing groups, merging paths, shortening colours and numbers. Typical savings are 30–80% for exported icons and illustrations. The main risks are a few transformations that can change appearance or break CSS and JavaScript that depend on IDs and classes, which a short configuration controls.
Rapid Diagnosis
- Open an exported SVG in a text editor. Look for
<metadata>,sodipodi:,inkscape:ordata-nameattributes,<!-- Generator: ... -->comments, and coordinates like12.000000. - Check sizes of SVG assets in the build output and of inline SVG in HTML.
- Check whether SVGO already runs. Many build setups optimise imported SVG components but not SVGs in
public/or CMS uploads. - Look for embedded rasters.
<image href="data:image/png;base64,…">inside an SVG means a bitmap disguised as a vector.
Root Cause Analysis
1. Editor-oriented exports. Tools preserve layer structure, names and metadata to support round-tripping.
2. Excess precision. Coordinates with five or six decimals are common; two or three suffice at typical display sizes.
3. Redundant structure. Empty groups, transforms that could be applied to paths, and duplicated style attributes.
4. No automation. Files are optimised once by hand, then replaced by new unoptimised exports.
Step-by-Step Resolution
1. Create a shared, safe configuration
// svgo.config.mjs
export default {
multipass: true,
floatPrecision: 2,
plugins: [
{ name: 'preset-default', params: { overrides: {
removeViewBox: false, // keep responsive scaling
cleanupIds: { minify: false }, // keep IDs referenced from CSS/JS
} } },
'removeDimensions', // size via CSS + viewBox instead of fixed width/height
{ name: 'removeAttrs', params: { attrs: ['data-name'] } },
],
};
// trade-off: removeDimensions suits icons styled by CSS; for <img> SVGs that
// rely on intrinsic size, drop it and set width/height on the img element.
2. Run it over existing assets
npx svgo --config svgo.config.mjs -rf src/assets/svg -o src/assets/svg
# trade-off: optimising in place is irreversible in the working tree; commit
# first so you can diff and review visual changes.
Expected outcome: smaller files with identical rendering for the vast majority of assets.
3. Integrate into the build
Use your bundler's SVG plugin with the same config so imported SVGs and copied assets are always optimised — for example vite-plugin-svgr or unplugin-icons with SVGO options, or svgo-loader/image-minimizer-webpack-plugin for webpack. For SVGs in public/ (copied verbatim), run SVGO as a pre-build step.
4. Guard against regressions in CI
Fail the build if an SVG asset is significantly larger than its optimised form, or simply run SVGO in check mode and compare sizes.
Verification
Compare file sizes before and after, and visually diff a sample of icons and illustrations (render both versions to PNG with a headless browser and compare pixels). Check that CSS and JavaScript referencing SVG IDs or classes still work. For inline SVG, HTML size per page should fall accordingly.
Worked Example: A Marketing Site's Illustrations
A marketing site used 34 decorative illustrations exported from a design tool, averaging 96KB each, several inlined in the homepage HTML. The homepage HTML was 410KB uncompressed. Running SVGO with multipass and two-decimal precision reduced illustrations to an average of 38KB; three that contained embedded PNG textures were re-exported as AVIF images instead. Homepage HTML fell to 190KB, and LCP on mobile improved by about 150ms because the HTML — which contained the LCP heading — arrived sooner.
Choosing Precision
floatPrecision is the setting with the biggest effect on size and the main source of visual changes. Icons drawn on a 24-unit grid need little precision: one or two decimals are invisible at icon sizes. Detailed illustrations scaled to full width may show tiny distortions at one decimal; two or three are safer. Test at the largest size each asset is displayed. A useful habit is to set precision per asset class in configuration (icons, logos, illustrations) rather than one global value.
Common Mistakes
- Removing the viewBox. Breaks scaling when dimensions are removed or overridden.
- Minifying IDs used by CSS or scripts. Animations and styles that target IDs stop working.
- Optimising only once. Without build integration, new exports reintroduce bloat.
- Ignoring embedded rasters. SVGO cannot shrink base64 PNGs inside SVG meaningfully; re-export as a raster image.
Edge Cases
Accessibility attributes. Keep <title>, role and aria-* attributes on meaningful SVGs; check that your preset does not strip them.
Animated SVG. SMIL animations and CSS animations referencing internal IDs or classes need those preserved.
Sprites. Optimise individual icons before building a sprite; some sprite tools run SVGO themselves.
Third-party SVGs. Logos and badges from partners are often unoptimised; optimise copies you host.
FAQ
Is SVGO safe to run on every SVG?
The default preset is safe for the overwhelming majority of files. The exceptions are files whose IDs or classes are referenced externally and files that rely on dimensions or viewBox behaviour — handled by the overrides above. Review diffs the first time you run it on an existing collection.
How much does SVGO save after gzip?
Less than the raw percentage suggests, because repetitive metadata compresses well — but still substantial, often 20–50% of compressed size, and the parse and DOM benefits apply to uncompressed size.
Should I use multipass?
Yes for build pipelines. It runs the plugins repeatedly until no further savings occur, which finds a few extra percent at the cost of slightly longer optimisation time.
Can SVGO convert shapes to paths?
Yes (convertShapeToPath, in the default preset), which often saves bytes. It can complicate later editing, which is why the source files should stay unoptimised in a design repository.
What about SVG in CSS data URIs?
Optimise them too, and URL-encode rather than base64-encode them for smaller output. For anything beyond tiny glyphs, prefer external files that cache separately from CSS.
Do image CDNs optimise SVG?
Some sanitize and minify SVGs; many pass them through unchanged. Do not rely on the CDN — optimise in the build where you control the configuration.
Should SVGO run on SVGs uploaded through a CMS?
Yes — user and editor uploads are often the least optimised assets on a site. Run SVGO (plus a sanitiser that removes scripts and event handlers, for security) on upload or in the image pipeline before files are published.
Does SVGO affect accessibility titles?
The default preset removes <title> in some versions (removeTitle). Disable that plugin for meaningful graphics, or provide accessible names on the referencing element instead.
How long does SVGO take in a build?
Milliseconds per file for icons and well under a second for large illustrations, so even hundreds of files add little build time. Cache results by content hash in CI if you have thousands of assets.
Related
- Inline SVG vs sprite vs img — what to do with optimised files.
- Reducing SVG rendering cost — beyond bytes.
- Precompressing static assets at build time — compressing SVG for delivery.