ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
Topics
sre111localhost lab102performance70python58javascript47bundle size36benchmarking35node.js35web development21typescript19benchmark16content creation15All topics
About
Loading article…

ShopperCove

Hands-on notes on developer tools, written after the tool has actually been run.

All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove

On this page

  1. What I tested
  2. How much did SVGO shrink the set?
  3. When is SVGR the right default?
  4. Should you switch SVG tooling?
  5. Sources
  6. Related
  1. Blog

SVGO vs SVGR: 34ms / 35% Smaller SVG Set

svgo 4.1.0 vs @svgr/core 8.1.0 on 20 verbose 128×128 SVGs (18,990 B). Warm medians (7 rounds after 1 warm-up): SVGO 34 ms / 12,410 B; SVGR JSX 35 ms / 17,620 B; SVGR+plugin-svgo 63 ms / 12,920 B. Fixture /workspace/bench-svgo-svgr/.

5 October 2026·4 min read

Hands-on
On this page
  1. What I tested
  2. How much did SVGO shrink the set?
  3. When is SVGR the right default?
  4. Should you switch SVG tooling?
  5. Sources
  6. Related

I ran 20 verbose SVG icons on this box: SVGO 4.1 median 34 ms and cut the set from 18,990 B to 12,410 B (~35% smaller). SVGR 8.1 turned the same files into React JSX in a median 35 ms (17,620 B of components).

Short answer: use SVGO when you ship static .svg assets. Use SVGR when the icons must be React components. Add @svgr/plugin-svgo when you want both (63 ms median here). No affiliate links in this post.

What I tested

  • Machine: 8 vCPU Intel Xeon / 15 GB RAM shared Linux cloud box, tested 6 Oct 2026 about 00:22–00:23 IST.
  • Versions: svgo 4.1.0; @svgr/core 8.1.0 with @svgr/plugin-jsx and @svgr/plugin-svgo; Node 22.20.0.
  • Fixture: /workspace/bench-svgo-svgr/icons/. Twenty hand-made 128×128 SVGs with XML prolog, comments, unused xmlns:xlink, empty defs, and verbose attributes (18,990 B total).
  • Runs: (1) svgo optimize multipass write .svg; (2) @svgr/core + plugin-jsx only; (3) @svgr/core + plugin-svgo + plugin-jsx. Timing via performance.now around each full 20-file pass. 1 warm-up + 7 interleaved rounds.
  • Findings: SVGO median 34 ms (min 30 / max 43), out 12,410 B. SVGR-only median 35 ms (33–40), out 17,620 B JSX. SVGR+SVGO median 63 ms (56–75), out 12,920 B JSX.
  • One surprise: SVGR alone was almost as fast as SVGO on this small set, but the JSX stayed larger than the optimized SVG until the SVGO plugin ran.
  • Not tested: @svgr/cli webpack/vite loaders, TypeScript output, native SVG sprites, React Native, animated SVG, SVGO browser build, Windows or macOS.

How much did SVGO shrink the set?

PathMedian wallMin / MaxOutput bytes
SVGO 4.1 multipass (.svg)34 ms30 / 4312,410 B
SVGR 8.1 JSX only35 ms33 / 4017,620 B
SVGR + plugin-svgo63 ms56 / 7512,920 B

Source total was 18,990 B across 20 files. SVGO removed about 35% of the bytes and kept .svg on disk. SVGR trades file size for importable components. For asset-weight budgets after icons land in a bundle, see size-limit vs bundlesize and source-map-explorer vs webpack-bundle-analyzer.

When is SVGR the right default?

Pick SVGR when icons need props, theming, or tree-shaken imports inside React. The plain JSX path here finished in 35 ms median — fine for a 20-icon set. Turn on @svgr/plugin-svgo if you care about the JSX byte count; that path cost 63 ms and landed near the SVGO-optimized size.

Stay on SVGO alone for static public/ icons, email HTML, or any pipeline that never imports SVG as a component. Pairing SVGO with a CSS toolchain decision is closer to Lightning CSS vs PostCSS than to a React transform.

Should you switch SVG tooling?

SituationMy pick
Static .svg in public/ or CMS uploadsSVGO
React icon components with propsSVGR (+ plugin-svgo)
Both static assets and React importsSVGO for assets; SVGR for components
Huge icon monorepos in CIMeasure; this lab was only 20 files
Raster thumbnails, not vectorsSee Sharp vs Jimp instead
Vite app watching total asset weightPair with Vite vs Parcel​

Bottom line: on 20 verbose icons, SVGO returned in 34 ms median and cut ~35% of the bytes; SVGR made JSX in 35 ms; SVGR+SVGO needed 63 ms. Who should not switch: teams already happy with an SVG sprite sheet and no React icon imports.

How this was made: I generated 20 noisy SVG fixtures on the ShopperCove box, installed svgo and @svgr/core with the JSX and SVGO plugins, timed interleaved 20-file passes after a warm-up, recorded JSON medians and output bytes; the write-up was drafted with AI help and checked against that output.

Sources

  • 01svgo.devhttps://svgo.dev/
  • 02github.com/svg/svgo
  • 03react-svgr.comhttps://react-svgr.com/
  • 04npmjs.com/package/svgo
  • 05npmjs.com/package/@svgr/core

Related

  • 01shoppercove.com/blog/unocss-vs-tailwind
  • 02shoppercove.com/blog/dprint-vs-prettier
  • 03shoppercove.com/blog/oxlint-vs-eslint
svgosvgrsvgreactjsxbenchmarkingoptimizationweb performance

Lab evidence

What I found running this

Hands-on on ShopperCove box 6 Oct 2026 ~00:22–00:23 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 22.20.0). svgo 4.1.0 vs @svgr/core 8.1.0 (+ @svgr/plugin-jsx, @svgr/plugin-svgo). Fixture /workspace/bench-svgo-svgr/: 20 verbose 128×128 SVGs, 18,990 B total; (1) SVGO multipass, (2) SVGR JSX only, (3) SVGR+plugin-svgo. 1 warm-up + 7 interleaved rounds. Medians SVGO 34 ms (30–43) / 12,410 B; SVGR 35 ms (33–40) / 17,620 B; SVGR+SVGO 63 ms (56–75) / 12,920 B. Raw: /workspace/bench-svgo-svgr/res-svgo-svgr.json. Not tested: loaders, TS output, sprites, React Native, animated SVG, Windows/macOS. No affiliate.

Notes when a lab post goes up

Occasional email for new hands-on reviews. No sequence and no sponsors.

Keep reading

  • Jotai vs Zustand: 0.15 ms vs 0.17 ms per Update

    Hands-on6 Oct 20265 min read

  • Yarn Berry vs pnpm: 1.3s vs 0.24s Install

    Yarn 4.9.2 (Berry PnP + node-modules linker) vs pnpm 12.9.1 on one 22-dependency React+Vite app. Isolated caches (Yarn enableGlobalCache false; pnpm --store-dir). Warm medians (5): Yarn PnP 1.307 s, Yarn nm 2.471 s, pnpm 0.240 s. Lock+empty medians 1.656 / 2.789 / 0.725 s. Clean disk: Yarn PnP 246 MB; Yarn nm modules 189 MB; pnpm hardlink project 167 MB. Fixture /workspace/bench-yarn-pnpm/. Distinct from pnpm-vs-npm-vs-bun (no Yarn).

    Hands-on6 Oct 20264 min read

  • Should You Leave PostCSS? 3ms vs 106ms

    Lightning CSS 1.33.0 vs PostCSS 8.5.29 + Autoprefixer 10.6.1 + cssnano 6.1.2 on a 76,864-byte CSS fixture: medians 3.16 ms vs 105.75 ms (~33x). Outputs 70498 vs 68474 B. Leave Autoprefixer+cssnano-only stacks for Lightning; keep PostCSS for plugins Lightning does not replace.

    Summary5 Oct 20264 min read