Make SVGO Optimizations Deterministic with Declarative Plugin Order and Multipass
Build a reproducible SVGO pipeline using declarative plugin order, isolated testing, and optional multipass convergence with clear checks and rollback.
28 Mar 2026, 13:44 UTC

The problem: unpredictable size wins and unsafe removals
SVGO can shrink SVGs aggressively, but the same input can produce different output when plugin order changes, when multipass is toggled, or after a major version upgrade. The useful takeaway is to treat optimization as an ordered set of AST transformations with a project-local declarative config, and to verify each plugin in isolation before allowing multipass convergence.
Desired outcome
A reproducible build step that reduces SVG size deterministically for a given config and input, with per-plugin safety controls and a clear rollback path when rendering or accessibility changes.
Prerequisites
- Node.js installed locally. Run commands in a project working directory with write access.
- SVGO available as CLI or programmatic dependency. Example install scope:
npm i -D svgo. - A representative corpus of SVGs under version control, e.g.,
assets/icons/. - A minimal
svgo.config.jsorsvgo.config.jsonin project root for declarative config.
Core engineering decision to leverage
SVGO parses SVG into an XML AST and applies optimizations as discrete, composable plugins that transform nodes in place. The pipeline is assembled and ordered by config. Staying in the text AST domain avoids rasterization and external libraries, which keeps the process fast, reproducible and suitable for CI. Output is deterministic for a given config and input, which supports caching and diffing.
Why order matters
Later plugins often assume earlier cleanup, e.g., removeDoctype before cleanupAttrs. Changing order can change results or safety. Plugin isolation lets you test one change at a time.
Focused procedure
1. Create a project-local declarative config
Create svgo.config.js with a safe baseline and explicit plugin list. This avoids implicit defaults that change between major versions.
// svgo.config.js
module.exports = {
multipass: false,
plugins: [
'removeDoctype',
'removeXMLProcInst',
{ name: 'removeComments', params: { preserveComment: true } },
{ name: 'removeMetadata', params: { stripMetadata: false } },
{ name: 'cleanupAttrs', params: { newlines: false } },
{ name: 'removeUselessDefs' }
]
};
Run from project root with read access to source SVGs and write access to output directory.
npx svgo --config=svgo.config.js assets/icons/input.svg -o dist/icons/input.svg
2. Verify plugin isolation
Enable a single plugin to confirm its effect on structure and size.
// svgo.config.js minimal test
module.exports = {
multipass: false,
plugins: [
{ name: 'removeUselessDefs', active: true }
]
};
Compare input and output size and structure. Disable the plugin and re-run to confirm the specific construct is preserved. This demonstrates plugin isolation and supports incremental adoption.
3. Add multipass convergence with a limit
Multipass re-runs the full plugin set until output stabilizes, exposing reductions from interdependent transformations.
module.exports = {
multipass: true,
plugins: [ /* same ordered list */ ]
};
Risk: increased CPU time and potential masking of non-idempotent plugin behavior. Observe iteration count and final size on test files before enabling in CI.
4. Control safety for accessibility and metadata
SVGO makes safety opt-in via parameters. Example to preserve title/desc for accessibility:
{ name: 'removeTitle', active: false },
{ name: 'removeDesc', active: false }
Expected checks
- Size and structure diff: compare input vs output byte size and node count. Use
git diffon a sample file to verify deterministic output. - Config validation: provide an unknown plugin name and confirm the tool rejects it with a schema validation error.
- Cross-interface consistency: apply the same config via CLI and programmatic API on identical input and compare outputs for consistency.
- Visual regression: SVGO operates on text only and cannot detect rendering differences. Render a sample set in a browser or visual diff tool to check for unintended changes to animation, stroke, or layout.
Recovery options
Because the operation changes files, keep originals in version control.
- Revert config: comment out or set
active: falsefor the suspect plugin and re-run. - Rollback files:
git checkout -- assets/icons/restores original SVGs. - Pin config per major version: review default plugin sets after upgrades, as behavior is version-sensitive.
Limitations
SVGO cannot detect rendering differences that require a browser or renderer. Aggressive plugins can remove or alter attributes that affect rendering, animation or accessibility. Multipass increases processing cost. Plugin order is significant and should be documented.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.