SVGO: What preset-default Removes and How overrides Put It Back
SVG Optimizer for Node.js and CLI. ⚙️
At a glance
- What is it?
- SVGO is a Node.js library and command line application that strips surplus from exported SVG files through a plugin pipeline. Its config surface is small, its plugin order is fixed, and the README documents no dry run.
- Who is it for?
- SVGO fits a build step that receives SVG files from somewhere else: CI, a CMS export, a design handoff, any file written by a tool you do not control. It does not fit a team that needs to diff original against optimized output before accepting the change, because the CLI documents no dry run, no undo and no per file log.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- svg/svgo22,817 ★ · +128
| Repository | 2026-09-21 | 2026-11-14 |
|---|---|---|
| svg/svgo | 22.7k | 22.8k |
128 Stars in the last 54 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
What gets deleted is editor leftovers, not pixels
Export an SVG from a vector editor and the file carries more than the drawing: editor metadata, comments, hidden elements, default or suboptimal values. SVGO exists to delete that surplus, and the deletion happens on a parsed representation of the markup rather than on a raster image. Nothing in the package deals with pixels. The result of the `optimize` function is an SVG string, and `js2svg` only controls how that string is laid out. If your problem is a 4 MB exported icon with two hundred kilobytes of commentary in it, this is the right shape of tool. If your problem is an illustration that renders differently across browsers, SVGO is the wrong one, because it is not asked to change rendering at all.
preset-default runs in a fixed order, and overrides are the only lever
You get optimization by naming `'preset-default'` in the `plugins` array, and that preset is a list of plugins that execute in a documented order rather than one switch. The single lever for changing it is the `overrides` object inside its params: `cleanupIds: false` disables a default plugin, and `inlineStyles: { onlyMatchedOnce: false }` changes a default plugin's parameters. One setting per plugin and nothing more. Switching a plugin off gives up whatever it was removing, and no per file or per element exemption is documented, so a document that needs a plugin kept on while leaving part of the file untouched cannot be described in this config format. Practical consequence: keep two config files, a plain preset-default for artwork your own code ships and an overridden preset for files that came out of someone else's editor.
npm, yarn or pnpm, then one command over a folder
SVGO ships on npm as `svgo`. Three global installs are given, and the only difference between them is the package manager you already run. Drop the global flag and the same names install it inside a project.
# npm
npm install -g svgo
# yarn
yarn global add svgo
# pnpm
pnpm add -g svgoTwo named files go in, two named files come out. Output paths follow `-o` rather than the inputs, which matters when the output names differ:
svgo one.svg two.svg -o one.min.svg two.min.svgFor a tree of files, add `-r` for recursion and `-f` for the folder itself:
svgo -rf path/to/directory_with_svgs -o path/to/output_directoryRead that line twice. Input directory and output directory are separate arguments. Copy the source tree before the first sweep. Anything beyond these flags lives behind the help screen:
svgo --helpmultipass, datauri and js2svg decide the shape of the output string
Three keys in `svgo.config.mjs` sit above the plugin list: `multipass` as a boolean, `datauri` with the values `'base64'`, `'enc'` and `'unenc'`, and `js2svg` holding `indent` and `pretty`. Two things the config file leaves unsettled. The file example writes `multipass: false` while the API example passes `multipass: true`, and no default is stated anywhere, so set it rather than inherit a guess. The `datauri` comment names three accepted values without explaining what each one does. The one thing the config file cannot do is point elsewhere, which is what `--config path/to/config.mjs` is for.
A custom plugin gets (ast, params, info) and an empty body
A plugin can be imported from another JavaScript file or defined inline, and the hook is `fn: (ast, params, info) => {}`. Three arguments, and the example body is empty. No node types, no node properties, no description of what `info` carries. The contract you code against is therefore the source: the repository keeps its own plugins in `plugins/` and its core in `lib/`, and those files are where the AST model is actually defined. That is the real price of extending SVGO beyond the preset.
No dry run, so -o is the whole safety story
The README documents inputs, `-o`, `-r`, `-f`, `--config` and `--help`, and says some other parameters can be configured through command-line options, with `--help` for advanced usage. There is no documented preview, dry run, backup, undo or watch mode, and no flag that reports the bytes saved before writing. The consequence is direct: the first run over a directory cannot be taken back, and the only backup is the copy you made yourself. Nor is there any record of which plugin changed which file, so when an optimized asset renders wrong you bisect by editing `overrides` one entry at a time rather than by reading a log. Get that loop working before pointing this at assets you did not create.
Node 16, an ESM config file and three release lines in one day
The package declares `"type": "module"`, `"engines": { "node": ">=16" }`, `"bin": "./bin/svgo.js"` and `"packageManager": "[email protected]"`. So the command line tool is a Node program rather than a native binary: no Node runtime means no CLI, and anything below Node 16 is excluded. The `.mjs` extension on the config file follows from the ESM package type, which is also why every config example uses `export default`. The `exports` map carries a separate `./browser` entry, so the same code can be loaded outside Node. Upgrade cost shows up in the release list: v4.1.0, v3.3.5 and v2.8.4 were all published on 2026-08-24, and the last push was on 2026-10-26. Parallel major lines moving on the same day means a plugin you wrote against one major is worth rechecking against the next. Licence is MIT.
Export time settings versus cleaning the file afterwards
The alternative to running SVGO is setting the export options in the vector editor so the surplus never gets written. The difference is where the work happens. Editor side settings apply to files that one editor produces, at the moment of export, and the person exporting sees the result immediately. SVGO is tool agnostic: `optimize` takes a string and returns a string, so it also handles files that arrived from a build step, a download or a snippet someone pasted into a ticket, and it runs in CI where nobody is clicking export. What the post export route gives up is the ability to change anything already lost and the chance to notice breakage at export time. A generic XML minifier is a third path, and it can shrink whitespace and attributes but has no SVG node model, so it cannot make the editor aware decisions. Split by source: editor settings for your own artwork, SVGO for the files you did not make.
Editorial conclusion
SVGO fits a build step that receives SVG files from somewhere else: CI, a CMS export, a design handoff, any file written by a tool you do not control. It does not fit a team that needs to diff original against optimized output before accepting the change, because the CLI documents no dry run, no undo and no per file log. It does not fit a machine without Node 16, since the binary is a Node script. Before adopting it, copy one folder, run `svgo -rf path/to/directory_with_svgs -o path/to/output_directory` on the copy, and open the result in a browser. Then switch one plugin off at a time through `overrides` until the diff stops surprising you. MIT licensed, three release lines moving on the same day, last push on 2026-10-26.
Frequently asked questions
What is SVGO and what is it used for?
SVGO is a Node.js library and command line application for optimizing SVG files. It removes editor metadata, comments, hidden elements and default or suboptimal values that can be dropped or converted without affecting rendering.
Does SVGO need Node.js installed to use the command line version?
Yes. The package sets `"engines": { "node": ">=16" }` and points its bin at `./bin/svgo.js`, so the CLI runs as a Node script rather than a standalone native executable.
How do I stop SVGO from removing something I need?
Set the offending plugin to false inside the `overrides` object of `preset-default`, as with `cleanupIds: false`, or pass different params such as `inlineStyles: { onlyMatchedOnce: false }`. The README does not document an exemption for a single file or a single element.
How do I load svgo.config.mjs from a Node script?
Call `loadConfig()` to resolve the config file, or pass a path and a working directory as `loadConfig(configFile, cwd)`. The same file can be selected from the command line with the `--config path/to/config.mjs` option.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/svg-svgo)Star history chart for your README
[](https://hysenlabs.com/projects/svg-svgo)Was this useful?