← All Articles · · 10 min read

SVG Optimization Best Practices for Web (2025)

How to optimize SVG files for the web. Covers SVGO, manual optimization techniques, inline vs external SVG, accessibility, animation performance, and free online SVG tools.

svgperformanceoptimizationfrontendimagesweb-development

SVG is the native format for scalable web graphics — icons, logos, charts, illustrations — and it’s often the most overlooked performance opportunity on a page. A fresh Figma export can be 10x larger than it needs to be.

This guide covers how to optimize SVGs systematically: automated tools, manual techniques, delivery strategies, and common mistakes to avoid.


Why SVG Optimization Matters

An unoptimized SVG from a design tool contains:

  • Editor metadata (<sodipodi:namedview>, <dc:format>, etc.)
  • Unused definitions and symbols
  • Redundant id attributes
  • Default attribute values that browsers assume anyway
  • Unnecessary whitespace and comments
  • Verbose path data (more decimal places than needed)
  • Empty groups and redundant transform attributes

A typical Figma icon export might be 4KB. After optimization: 800 bytes. Multiply that across 50 icons on a page.


Tool 1: SVGO (The Standard)

SVGO (SVG Optimizer) is the industry standard for SVG optimization. It’s what most other tools use under the hood.

Install:

npm install -g svgo

Basic usage:

# Optimize a single file (overwrites original)
svgo icon.svg

# Output to a new file
svgo icon.svg -o icon.min.svg

# Optimize all SVGs in a directory
svgo -f ./src/icons/ -o ./dist/icons/

# Show how much was saved
svgo icon.svg --pretty

Configuration file (svgo.config.js):

module.exports = {
  plugins: [
    'preset-default',
    {
      name: 'removeViewBox',
      active: false,  // Keep viewBox for responsive scaling
    },
    {
      name: 'removeDimensions',
      active: true,  // Remove width/height (use CSS instead)
    },
    {
      name: 'prefixIds',
      params: {
        prefix: 'icon-',  // Prefix IDs to avoid conflicts when inlining
      },
    },
  ],
};

Common flags to know:

# Multipass (multiple optimization rounds)
svgo --multipass icon.svg

# Disable a specific plugin
svgo --disable=removeViewBox icon.svg

# Pretty print (readable output)
svgo --pretty icon.svg

Tool 2: Online SVG Optimizers

For one-off optimizations without installing anything:

  • SVGOMG (jakearchibald.github.io/svgomg): GUI interface for SVGO with toggle-able plugins and live preview
  • Nano SVG (vecta.io/nano): Alternative optimizer with its own algorithm

These are ideal for quickly checking what’s safe to remove before committing to settings.


Manual Optimization Techniques

Some optimizations require human judgment that automated tools can’t make.

1. Remove Unnecessary Metadata

Figma exports include metadata that’s meaningless for web display:

<!-- Remove this -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:cc="http://creativecommons.org/ns#"
     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
     xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.0.dtd"
     xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape">
  <sodipodi:namedview />
  <rdf:RDF>...</rdf:RDF>

<!-- Keep this -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">

2. Simplify Paths

Overly precise paths have more decimal places than screens can render:

<!-- Before: 6 decimal places -->
<path d="M12.000000 4.000000 L20.000000 20.000000 L4.000000 20.000000 Z"/>

<!-- After: 1-2 decimal places is sufficient -->
<path d="M12 4 L20 20 L4 20Z"/>

SVGO’s roundPathData plugin handles this automatically, but you can set the precision:

{
  name: 'roundPathData',
  params: { precision: 2 }
}

3. Merge Similar Elements

Design tools often export individual elements that could be combined:

<!-- Before: 3 separate paths with identical fill -->
<path fill="#333" d="M..."/>
<path fill="#333" d="M..."/>
<path fill="#333" d="M..."/>

<!-- After: one group with the shared attribute -->
<g fill="#333">
  <path d="M..."/>
  <path d="M..."/>
  <path d="M..."/>
</g>

4. Replace Generic Shapes With SVG Primitives

Design tools sometimes export rectangles and circles as <path> elements. Replace them with semantic SVG:

<!-- Instead of a path that draws a circle -->
<path d="M 100 50 A 50 50 0 1 0 100 50.001 Z"/>

<!-- Use the circle primitive -->
<circle cx="100" cy="50" r="50"/>

Primitives are smaller and more readable.

5. Remove Invisible Elements

Clean up clipping masks and invisible elements:

<!-- Invisible elements waste bytes -->
<rect width="24" height="24" fill="none"/>  <!-- Remove -->
<path opacity="0" d="..."/>                  <!-- Remove -->

Inline SVG vs External SVG

Use Inline SVG When:

  • Icons that change color via CSS (:hover, dark mode)
  • SVGs that need JavaScript interaction
  • Critical above-the-fold icons (saves an HTTP request)
  • Animated SVGs
<!-- Inline: directly in HTML, styleable via CSS -->
<button class="btn">
  <svg viewBox="0 0 24 24" aria-hidden="true">
    <path d="M12 2L2 7l10 5 10-5-10-5z"/>
  </svg>
  Download
</button>
/* Color via CSS parent */
.btn:hover svg path {
  fill: white;
}

/* Dark mode support */
@media (prefers-color-scheme: dark) {
  svg path { fill: #e2e8f0; }
}

Use External SVG When:

  • Illustrations and complex graphics (cacheable)
  • SVGs used as <img> tags (no JS needed)
  • SVGs reused across many pages
<!-- External: cached by browser, simpler markup -->
<img src="/icons/logo.svg" alt="Company Logo" width="120" height="40">

SVG Sprite for Icon Systems

For many icons, a sprite reduces HTTP requests:

<!-- sprite.svg (loaded once) -->
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
  <symbol id="icon-search" viewBox="0 0 24 24">
    <path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
  </symbol>
  <symbol id="icon-user" viewBox="0 0 24 24">
    <path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/>
    <circle cx="12" cy="7" r="4"/>
  </symbol>
</svg>

<!-- Usage anywhere in the page -->
<svg aria-hidden="true"><use href="#icon-search"/></svg>
<svg aria-hidden="true"><use href="#icon-user"/></svg>

SVG Accessibility

Don’t forget accessibility when embedding SVGs:

<!-- Decorative icons (no semantic value) -->
<svg aria-hidden="true" focusable="false">
  <path d="..."/>
</svg>

<!-- Meaningful icons without visible text -->
<svg role="img" aria-labelledby="icon-title">
  <title id="icon-title">Search</title>
  <path d="..."/>
</svg>

<!-- SVG with visible label -->
<button>
  <svg aria-hidden="true">
    <path d="..."/>
  </svg>
  <span>Search</span>
</button>

Rule of thumb: if there’s visible text describing the action, use aria-hidden="true" on the SVG. If the SVG is the only indicator of meaning, add a <title>.


SVG Animation Performance

Animations have their own performance considerations:

CSS Animations (Preferred)

/* High-performance: only animates transform and opacity */
@keyframes spin {
  to { transform: rotate(360deg); }
}

.loading-icon {
  animation: spin 1s linear infinite;
  /* Promote to GPU layer */
  will-change: transform;
}

SMIL Animations (Avoid in Production)

SMIL (built-in SVG animations) has inconsistent browser support and poor performance. Prefer CSS or JavaScript (GSAP) animations instead.

Reduce Motion

Always respect the user’s motion preference:

@media (prefers-reduced-motion: reduce) {
  .animated-icon {
    animation: none;
  }
}

Build Pipeline Integration

Vite/webpack with vite-plugin-svgr

// vite.config.js
import svgr from 'vite-plugin-svgr';

export default {
  plugins: [svgr()],
};

// Usage in React
import { ReactComponent as SearchIcon } from './search.svg';

function SearchButton() {
  return (
    <button>
      <SearchIcon className="icon" aria-hidden="true" />
      Search
    </button>
  );
}

SVGO in package.json scripts

{
  "scripts": {
    "optimize-icons": "svgo -f src/icons/ -o public/icons/ --multipass",
    "prebuild": "npm run optimize-icons"
  }
}

Quick Optimization Checklist

Before shipping an SVG:

  • Ran through SVGO with --multipass
  • viewBox preserved (for responsive scaling)
  • width/height removed (let CSS control size)
  • No editor metadata (Inkscape, Illustrator namespaces)
  • IDs prefixed if used inline (avoid collisions)
  • Accessibility attributes set (aria-hidden or aria-label)
  • Reduced motion considered for animated SVGs
  • Paths rounded to 1-2 decimal places


Download the Frontend Performance Checklist

The Frontend Performance Audit Checklist covers SVG optimization alongside image formats, font loading, bundle splitting, and Core Web Vitals — a complete audit you can run on any web project.

Free Newsletter

Level Up Your Dev Workflow

Get new tools, guides, and productivity tips delivered to your inbox.

Plus: grab the free Developer Productivity Checklist when you subscribe.

Found this guide useful? Check out our free developer tools.