UseToolSuite UseToolSuite

SVG Optimization: Reduce File Size Without Losing Quality

A practical guide to optimizing SVGs: configuring SVGO, merging paths, truncating coordinate precision, and using the `<use>` tag to cut DOM size — plus when not to use SVG.

Necmeddin Cunedioglu Necmeddin Cunedioglu 6 min read
Part of the The Complete Guide to Browser-Based Image Editing series

Practice what you learn

SVG Optimizer

Try it free →

SVG Optimization: Reduce File Size Without Losing Quality

Scalable Vector Graphics (SVG) are a backbone of responsive web design. Unlike raster formats (JPEG, PNG, WebP) that store a grid of pixels, SVGs use mathematical vectors to draw shapes. A 2KB SVG logo renders sharp on a 4K monitor and on a phone’s Retina display without adding a single byte.

But SVGs have a catch. Because they’re just XML text, the files exported by Figma, Illustrator, or Inkscape are usually bloated — packed with editor metadata, redundant attributes, invisible layers, and excessive decimal precision the browser doesn’t need.

That bloat affects your Core Web Vitals. Large inline SVGs expand the DOM tree, slow First Contentful Paint, and use more memory. This guide covers the SVG DOM, how to strip bloat with SVGO, path-merging, and the rules for when to use SVG versus a raster format like WebP.

Optimize SVGs instantly: paste raw SVG code into our SVG Optimizer to strip metadata, minify coordinates, and cut the byte count — all locally in your browser.

1. What Gets Removed

When you run an SVG through an optimizer, it targets four categories of bloat.

A. Editor metadata

When you export from Figma or Illustrator, the software embeds proprietary XML namespaces and metadata describing the document. The browser ignores it all on load — it only exists so the file can be reopened in the design tool later.

<!-- ❌ Bloated: Figma metadata and unnecessary namespaces -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Figma 116.3.3 -->
<svg xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"
     version="1.1" id="Layer_1" x="0px" y="0px"
     xml:space="preserve">
  <metadata />
    <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
      <rdf:Description rdf:about="" dc:title="Brand Logo Master"/>
    </rdf:RDF>
  </metadata>
  <!-- The actual shapes start here -->
</svg>

After optimization: the optimizer strips the DOCTYPE, comments, namespaces, and the <metadata /> block, leaving only the wrapper the browser needs:

<!-- ✅ Optimized -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
  <!-- Actual shapes start here -->
</svg>

B. Redundant attributes and default values

Design tools often set attributes that match the W3C defaults, which wastes bytes.

<!-- ❌ Bloated: explicitly setting default values -->
<rect x="0" y="0" width="100" height="100"
      fill="black" fill-opacity="1" stroke="none"
      stroke-width="1" stroke-dasharray="none" opacity="1"/>

<!-- ✅ Optimized: the browser assumes these defaults -->
<rect width="100" height="100"/>

C. Empty groups and invisible elements

Complex illustrations often contain hidden layers, empty <g> tags from copy-pasting, or zero-opacity shapes used as designer alignment guides.

<!-- ❌ Bloated: invisible layers and empty groups -->
<g id="Designer_Alignment_Guides" display="none">
  <rect width="50" height="50" fill="#FF0000"/>
</g>
<g id="Empty_Semantic_Wrapper">
  <circle cx="50" cy="50" r="40" opacity="0"/>
</g>

A good optimizer walks the DOM tree and deletes any node that has no effect on the final output.

D. Excessive coordinate precision

This is usually where the biggest savings come from. Path coordinates from design tools often carry absurd floating-point precision.

<!-- ❌ Bloated: unnecessary decimal places -->
<path d="M 12.34567891 45.67891234 L 78.12345678 90.98765432"/>

Since monitors operate on an integer pixel grid, precision beyond two or three decimals is invisible. Optimizers round these down safely.

<!-- ✅ Optimized: rounded to 2 decimals, whitespace stripped -->
<path d="M12.35 45.68L78.12 90.99"/>

2. The SVG DOM and Render Performance

The key thing to understand is that SVG files aren’t just images — they’re XML documents.

When you embed a raw SVG into a React component or HTML file (inline SVG), the browser parses every <path>, <circle>, and <g> node and injects it into the DOM tree.

If a designer exports an illustration with 5,000 paths, inlining it adds 5,000 nodes to your DOM. That forces the browser to spend CPU and memory on layout, style recalculation, and paint — leading to scroll jank and dropped frames on mid-tier phones.

Path merging

The most powerful optimizer step is path merging. If an SVG has 50 separate <circle> elements sharing the same fill and opacity, the optimizer can merge them into a single <path> with one d="" attribute.

That takes the DOM footprint from 50 nodes down to 1, saving file size and speeding up parsing and rendering.

The <use> tag and Shadow DOM

For an icon repeated across a page (a green checkmark used 20 times in a pricing table), don’t paste the SVG markup 20 times. Use the <use> element to clone it efficiently.

<!-- 1. Define the graphic ONCE -->
<svg style="display:none">
  <defs>
    <symbol id="icon-checkout-check" viewBox="0 0 24 24">
      <path d="M20 6L9 17l-5-5"/>
    </symbol>
  </defs>
</svg>

<!-- 2. Reference it 20 times with a single line each -->
<ul>
  <li><svg class="icon"><use href="#icon-checkout-check"/></svg> Feature 1</li>
  <li><svg class="icon"><use href="#icon-checkout-check"/></svg> Feature 2</li>
</ul>

Why it matters: when the browser hits a <use> tag, it renders the cloned paths inside an isolated Shadow DOM. The checkmark’s internal paths are NOT added to the main DOM 20 times. This saves memory and parse time while still letting external CSS style the icon.

3. SVGO: The Standard Optimizer

Nearly every optimization tool (including ours and the ImageOptim desktop app) is built on SVGO, a configurable Node.js tool that runs a series of plugins.

A production-ready svgo.config.js might look like this:

module.exports = {
  multipass: true, // Run the sequence repeatedly until no further changes occur
  plugins: [
    'removeDoctype',
    'removeXMLProcInst',
    'removeComments',
    'removeMetadata',
    'removeEditorsNSData',
    'cleanupAttrs',
    'mergeStyles',
    'inlineStyles',
    'removeUselessDefs',
    'cleanupNumericValues',
    'convertColors',       // Converts #FFFFFF to #FFF to save 3 bytes per color
    'removeUnknownsAndDefaults',
    'removeNonInheritableGroupAttrs',
    'removeUselessStrokeAndFill',
    'cleanupIds',
    'removeEmptyContainers',
    'mergePaths',          // The DOM-reducing node-merging step
    'convertPathData',     // The coordinate-rounding step
  ],
};

Plugins to avoid

Aggressive optimization is usually good for file size, but a few SVGO plugins can break functionality. Disable these:

  1. removeViewBox: the viewBox is what lets an SVG scale responsively with CSS width/height. Removing it locks the SVG to fixed dimensions. Never enable this.
  2. convertShapeToPath: converts shapes (<circle>, <rect>) into path data. If your CSS animations target a specific <circle>, this breaks them.
  3. cleanupIds: removes id="" attributes from elements. If your CSS or JavaScript targets internal SVG elements by ID, this breaks your styles and interactivity.

4. CSS Integration: the currentColor Strategy

A big advantage of inline SVGs over PNG/WebP is that you can restyle them with CSS. To do that, strip hardcoded hex colors and replace them with the currentColor keyword.

<!-- ❌ Unoptimized: locked to a hardcoded color -->
<svg viewBox="0 0 24 24">
  <path fill="#333333" d="..."/>
</svg>

<!-- ✅ Optimized: theme-aware -->
<svg class="dynamic-theme-icon" viewBox="0 0 24 24">
  <path fill="currentColor" d="..."/>
</svg>

With currentColor, the SVG inherits the text color of its parent. That lets you support dark mode and hover states with CSS, without downloading multiple image files.

.dynamic-button-container {
  color: #333333; /* The SVG inherits this dark gray */
}

.dynamic-button-container:hover {
  color: #007BFF; /* The SVG turns blue on hover */
}

/* Dark mode support */
@media (prefers-color-scheme: dark) {
  .dynamic-button-container {
    color: #F0F0F0; /* The SVG turns light gray in dark mode */
  }
}

5. When NOT to Use SVG

As useful as SVG is, it’s the wrong choice for complex, dense images. Forcing an illustration with heavy gradients, drop shadows, and hundreds of thousands of nodes into XML produces a multi-megabyte file and poor render performance.

FormatTechnologyBest forScalabilitySize
SVGVectors (XML DOM)Logos, UI icons, simple illustrationsInfiniteTiny for simple shapes, huge for complex art
WebPRaster (modern compression)Photos, 3D art, dense gradientsFixedWell compressed
PNGRaster (lossless)Screenshots, transparency on legacy browsersFixedLarge and inefficient
JPEGRaster (lossy)Photos without transparencyFixedModerate to small

Rule of thumb: if the image has fewer than ~1,000 paths and mostly flat colors, use SVG. If it’s a photo, a 3D render, or a detailed painting with complex lighting, export it as WebP.

Further Reading


Part of our web performance series. Optimize vector graphics locally with our SVG Optimizer, compress raster photos with the Image Compressor, and strip whitespace from your code with the CSS Minifier.

Necmeddin Cunedioglu
Necmeddin Cunedioglu Author
6 min read
-- views

Software developer and the creator of UseToolSuite. I write about the tools and techniques I use daily as a developer — practical guides based on real experience, not theory.