Clean SVG Exports from Figma: A Practical Guide

·9 min read

Figma is the most-used design tool for web work, and shipping the SVGs it exports without optimisation is one of the most reliable ways to bloat a web page. Pristine icons that look 200 bytes worth of complex come out as 3 KB blobs of nested groups, repeated clip-path definitions, six-decimal coordinates, and inline styles. This is fixable, and most of the fix happens in Figma itself before you ever touch a build step.

Why Figma exports are bloated

Figma was not built to produce production SVG. It was built to produce roundtrippable SVG — files that can be re-imported back into Figma and look the same. That goal is in direct conflict with smallness: to roundtrip, Figma has to preserve layer hierarchy, stroke metadata, blend modes, alignment information, and every other design-time attribute that the renderer doesn’t need. The result is functionally correct and aesthetically wasteful.

A typical 32×32 line icon — one stroke, three or four path commands — exports as something between 1.5 and 5 KB. The same icon hand-coded or run through SVGO ends up at 200 to 400 bytes. The difference is almost entirely structural overhead. Multiply that by every icon in a sidebar and you have shipped a hundred kilobytes that does not need to exist.

Where the bytes go in a Figma SVG exportTwo stacked horizontal bars compare a raw Figma export to a cleaned version. The raw export is roughly 3,300 bytes, broken down into: numeric precision (1100 bytes), empty group wrappers (540), clip-path definitions (420), IDs and data-name attributes (360), inline style attributes (280), and the actual path data (600 bytes). The cleaned version contains only the 600 bytes of actual path data — about an 81% reduction.Raw Figma export (3,300 bytes)1100540420360280600Numeric precisionEmpty <g> wrappersclip-path defsIDs / data-nameinline style attrsthe actual pathsAfter cleanup (600 bytes — 81% smaller)600

The five sources of bloat

1. Coordinate precision

The single biggest contributor. Figma exports path coordinates with four to six decimal places of precision: M 12.345678 9.87654 when M 12.35 9.88 is visually indistinguishable. A path that takes 1,200 bytes at full precision often takes 250 at two decimals. SVGO’s cleanupNumericValues plugin handles this, but Figma will not.

2. Empty group wrappers

Figma wraps every layer in a <g> element, even when the layer contains a single shape and the wrapper does nothing. A page of 50 icons with three layers each carries 150 empty groups that the renderer has to walk past.

3. clip-path on every frame

Figma frames have a “clip content” checkbox that is on by default, including for icon-sized frames where nothing is ever going to clip. Each clipped frame becomes a <defs> block with a <clipPath> definition and an unnecessary clip-path="url(#...)" attribute on the wrapping group.

4. IDs and data-name attributes

Every Figma layer name becomes both an id and a data-name attribute. This is occasionally useful for CSS targeting (which is why we don’t recommend stripping all IDs blindly), but for an icon library where you target with parent classes it is pure overhead. data-name in particular is purely Figma metadata and has no use in production.

5. Inline style attributes

Figma serialises fills and strokes as style="fill:#111;stroke:#000" rather than as presentation attributes (fill="#111" stroke="#000"). This costs a few bytes per element and, more importantly, makes CSS overrides harder — inline styles win specificity battles against stylesheet rules without !important.

Pre-export prep, in order

Most of the bloat above is preventable in Figma itself, before export. Walking the icon through this checklist takes about thirty seconds and shaves 60–80% before any optimisation tool runs.

  1. Disable “Clip content.” On the icon frame, in the right sidebar, uncheck Clip content. This kills the unnecessary clip-path. (Do this on the parent component, then on each instance — Figma propagates the property inconsistently.)
  2. Outline strokes. Select the path and press Cmd/Ctrl + Shift + O. This converts the live stroke into a fillable path. The result is a single <path> with a fill instead of a stroked shape, which is both smaller in bytes and renders identically across browsers (especially relevant for half-pixel-aligned strokes that otherwise blur).
  3. Flatten boolean ops. If you used Union, Subtract, Intersect, or Exclude to build the shape, select the result and press Cmd/Ctrl + E to flatten. Otherwise Figma exports each boolean operation as a separate path with a CSS blend or a fill-rule.
  4. Delete hidden layers. Hidden layers still get exported in many Figma states. Either delete them or move them outside the export frame.
  5. Rename layers to something useful. The layer name becomes the id. “Rectangle 47” in the export is a smell; id="bar" is at least descriptive.
  6. Set the export frame to the artwork bounding box. Resize the frame so it tightly encloses the artwork. Empty space in the frame becomes empty space in the viewBox, which throws off any sizing logic that assumes the icon fills its box.

The export settings dialog

Figma’s native SVG export options are minimal. The dialog gives you four checkboxes:

  • Outline text. Convert text to paths. Turn this on for icons (so they don’t depend on a font being available); turn it off for body text or when you want the text to remain accessible and stylable.
  • Include id attribute. Off by default; on if you want to keep your layer names as IDs for CSS targeting. We recommend leaving it off and using class-based selectors on the wrapping element.
  • Simplify stroke. Off by default. Turn this on — it converts strokes into more efficient path representations.
  • Flatten transforms. Bake transformation matrices into the path data instead of leaving them as transform="..." attributes. Turn this on.

That is the entire native interface. Everything else needs a plugin.

The plugins worth installing

The Figma community has produced a few SVG-export plugins that wrap SVGO and let you run it inside Figma instead of as a separate build step. Worth installing if you ship lots of icons:

  • Advanced SVG Export — gives you the full SVGO plugin matrix as a settings panel. Most powerful and most configurable. The right choice for an icon-library workflow.
  • Clean SVG Export — opinionated one-click optimisation. Strips empty groups, flattens, runs SVGO with sensible defaults. The right choice if you don’t want to think about settings.
  • SVG Export — batch-export many icons at once with a global setting for fill="currentColor" (essential for icon libraries that should inherit text colour).

Post-export: SVGO is non-optional

Even after a clean Figma export, run the result through SVGO. Either via a plugin during export, as a build step (Vite, webpack, rollup all have SVGO loaders), in your CI pipeline, or against the svg.dog API. The defaults are good enough for 95% of icons; for the rest, our SVGO guide covers which plugins to enable and disable for which situations.

The single most-impactful non-default setting: removeViewBox: false. SVGO strips the viewBox by default when it can compute width/height equivalents, which then makes the SVG impossible to scale responsively. Turn that off.

The currentColor trick for icon libraries

If you’re shipping an icon library, the single most important post-processing step is replacing every fill and stroke attribute with currentColor:

<svg viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
  <path d="M..." />
</svg>

This makes the icon inherit the surrounding text colour, so an icon inside a red error message turns red, an icon inside a muted help link turns grey, and an icon on a dark-mode page becomes light. No per-context CSS overrides, no separate light/dark icon variants. It is the single trick that distinguishes a usable icon set from a chore.

Some Figma plugins (notably SVG Export) have a one-click toggle for this. Doing it manually is a search-and-replace.

The recommended workflow

Putting it all together, the pipeline that produces clean, small, stylable SVG out of Figma:

  1. Design the icon. Use a single layer where possible.
  2. Disable Clip content, outline strokes, flatten booleans.
  3. Resize the frame to tight bounds.
  4. Export with Simplify stroke and Flatten transforms on.
  5. Run through SVGO with removeViewBox: false.
  6. Replace fills with currentColor (manually or via plugin).
  7. Commit the result.

For a single icon, this is twenty seconds of work. For a 200-icon library, set up a Figma plugin or a build step so the optimisation runs every time you re-export, and you never have to think about it again.

Why this matters more than it looks

A 3 KB icon doesn’t look like much. But icon-heavy interfaces (admin dashboards, design system documentation, Notion-style apps) ship hundreds of them, and the total adds up fast. We routinely see marketing sites where 60% of the page weight is unoptimised Figma SVG, and the fix is the checklist above.

The deeper reason: every byte you save on an icon is a byte saved on every page that uses it, on every visit, for every user, for the entire life of your product. Optimisation has the highest leverage of any work you do. It also takes thirty seconds.


Related: our SVGO guide covers the post-export optimisation step in depth, and Why SVG files are so large breaks down the same problem from the file-anatomy angle.

Optimize SVGs instantly — no setup needed

500 free optimizations per month. No credit card required.

Get a free API key →