How to Optimize SVG Files in Bulk
When you have a folder of icons, a downloaded icon library, or an SVG asset pipeline, you need to optimize files in bulk — not one at a time. Here are the most effective approaches.
SVGO CLI batch mode
SVGO supports folder input natively. Point it at a directory and it processes every.svg file it finds:
# Optimize all SVGs in ./icons, output to ./icons-min
npx svgo -f ./icons -o ./icons-min --multipass
# Optimize in place (overwrites originals!)
npx svgo -f ./icons --multipass
# Recursive: include subdirectories
npx svgo -r -f ./icons --multipassSVGO processes files sequentially by default. For large libraries (500+ icons), this can be slow. Use a parallel Node.js script for better throughput.
Parallel Node.js script
Process multiple files concurrently with a concurrency limit to avoid memory pressure:
// scripts/optimize-all-svgs.js
import { optimize } from 'svgo';
import fs from 'node:fs';
import path from 'node:path';
function collectSvgs(dir, results = []) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) collectSvgs(full, results);
else if (entry.name.endsWith('.svg')) results.push(full);
}
return results;
}
async function optimizeFile(filePath) {
const input = fs.readFileSync(filePath, 'utf-8');
const result = optimize(input, { multipass: true });
fs.writeFileSync(filePath, result.data);
return input.length - result.data.length;
}
async function run() {
const files = collectSvgs('./icons');
const CONCURRENCY = 10;
let saved = 0;
for (let i = 0; i < files.length; i += CONCURRENCY) {
const batch = files.slice(i, i + CONCURRENCY);
const savings = await Promise.all(batch.map(optimizeFile));
saved += savings.reduce((a, b) => a + b, 0);
}
console.log(`Optimized ${files.length} files, saved ${(saved / 1024).toFixed(1)} KB`);
}
run();svg.dog batch API endpoint
The svg.dog API has a /v1/optimize/batch endpoint that accepts multiple files in one request and returns them as a ZIP archive:
# CLI: batch upload with curl (up to 50 files)
curl -X POST https://api.svg.dog/v1/optimize/batch \
-H "Authorization: Bearer YOUR_KEY" \
-F "files=@icon1.svg" \
-F "files=@icon2.svg" \
-F "files=@icon3.svg" \
-o optimized.zipNode.js with the SDK:
import { optimizeBatch } from '@svg.dog/svgdog';
import fs from 'node:fs';
import path from 'node:path';
const iconDir = './icons';
const files = fs.readdirSync(iconDir)
.filter(f => f.endsWith('.svg'))
.map(f => fs.readFileSync(path.join(iconDir, f)));
const results = await optimizeBatch(files, {
apiKey: process.env.SVGDOG_API_KEY,
});
results.forEach((result, i) => {
fs.writeFileSync(path.join(iconDir, `${i}.svg`), result.svg);
console.log(`${i}.svg: ${result.savingsPercent.toFixed(1)}% saved`);
});Optimizing an icon library (e.g., Heroicons, Lucide)
If you downloaded an icon library and want to pre-optimize it before committing to your repo, here’s a one-liner that processes the entire node_modules install:
npx svgo -r -f ./node_modules/lucide-static/icons --multipassA better pattern: add an npm postinstall script that runs SVGO on the icon package after installation. This ensures the optimized version is always what your build picks up.
Shell script for simple pipelines
For projects without Node.js, a bash loop works fine for small icon sets:
#!/bin/bash
# optimize-icons.sh
for file in ./icons/*.svg; do
curl -s -X POST https://api.svg.dog/v1/optimize \
-H "Authorization: Bearer $SVGDOG_API_KEY" \
-F "file=@$file" \
-o "$file.tmp" && mv "$file.tmp" "$file"
echo "Optimized: $file"
doneTracking savings over time
For icon libraries that evolve, log the total size before and after each optimization run:
# Before
du -sh ./icons/
# After optimization
du -sh ./icons/Wiring this into a CI comment on pull requests gives your team a clear picture of asset health over time.
Integration with CI
Batch optimization works well as a scheduled CI job (e.g., nightly) rather than per-commit, especially for large icon libraries. See CI/CD automation for full workflow examples.
Optimize SVGs instantly — no setup needed
500 free optimizations per month. No credit card required.
Get a free API key →