{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreicc4jslaatanrc4nwaw3i4us3rmt3vxe5ft27l43g3otcjbwfcxca",
"uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3mqe7m4lbnlq2"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreihizaoaruijb5rgn4jcn7eo3sjecxf7m3ucgqwh2o444g47px2zqa"
},
"mimeType": "image/webp",
"size": 65992
},
"path": "/nathmaxx/convert-a-whole-folder-of-images-to-webp-locally-no-upload-one-command-42od",
"publishedAt": "2026-07-11T07:40:47.000Z",
"site": "https://dev.to",
"tags": [
"webdev",
"javascript",
"node",
"webperf",
"@assetopt/cli",
"reproduce these exact figures",
"Convert JPG & PNG to WebP in bulk — the full guide",
"@assetopt"
],
"textContent": "Every few months I hit the same wall: a folder full of `.jpg` and `.png` files that need to be WebP before they go anywhere near production. And every few months I catch myself doing the dumbest possible thing — dragging them one by one into some online converter, waiting for the upload, downloading them back, renaming them.\n\nIt doesn't scale, and honestly I'm never thrilled about uploading a client's assets to a random SaaS just to save a few kilobytes.\n\nSo the workflow below does the whole folder in **one command, locally** — nothing leaves your machine, no account, originals left untouched. It runs on @assetopt/cli (open source, MIT), a small CLI I've been building that optimizes images _and_ CSS, JS and SVG in one pass.\n\n## Why WebP at all\n\nWebP is typically **25–35% smaller** than an equivalent JPEG or PNG at matched quality. It's one of the cheapest wins available for page weight — the format is universally supported now, and the only friction left is _doing it in bulk without a painful workflow_.\n\n## Install\n\n\n npm install -g @assetopt/cli\n\n\nOr run it once, without installing anything:\n\n\n\n npx @assetopt/cli --help\n\n\n## The one-command version\n\nPoint `assetopt` at a folder and it recurses into it. By default it **recompresses images in their original format** — to turn JPG and PNG into WebP, you say so once in a config file.\n\nCreate a `.assetoptrc` that routes both source formats to WebP:\n\n\n\n {\n \"images\": {\n \"formatMatrix\": { \"jpeg\": \"webp\", \"png\": \"webp\" },\n \"quality\": { \"webp\": 82 }\n },\n \"output\": { \"dir\": \"./optimized\" }\n }\n\n\nThen convert the folder:\n\n\n\n assetopt optimize ./images\n\n\nEvery `.jpg` and `.png` under `./images` is written as `.webp` into `./optimized`, mirroring the source tree. Your originals stay exactly where they are.\n\n## Preview the savings before touching your disk\n\nThis is the part I actually use the most. `analyze` reports the exact before/after sizes as a dry run — it writes nothing:\n\n\n\n assetopt analyze ./images\n\n\nYou get a per-file table and a total. When the numbers look right, swap `analyze` for `optimize`.\n\n## Tune the quality, fast\n\nWebP quality is a 1–100 dial (default `82`). Lower means smaller files and more visible artifacts:\n\n\n\n { \"images\": { \"formatMatrix\": { \"jpeg\": \"webp\", \"png\": \"webp\" }, \"quality\": { \"webp\": 75 } } }\n\n\nRe-run `assetopt analyze ./images` after each change. There's an **incremental cache** on by default, so only the files you actually changed get re-encoded — tuning the quality dial is basically instant instead of re-crunching the whole folder each time.\n\n## Real numbers\n\nRunning the config above on a sample pack (JPG/PNG → WebP):\n\nSource | Before | After (WebP) | Saved\n---|---|---|---\nLarge PNG export (opaque photo) | 5.42 MB | 552 KB | **−89.8%**\nJPEG photo | 1.74 MB | 1.44 MB | **−17.4%**\n\nThe PNG loses the most, because a photo saved as PNG is hugely oversized to begin with — WebP is simply the right container for it. A photo already saved as JPEG is closer to optimal, so the win is smaller but still real. You can reproduce these exact figures by downloading the pack and running the commands above.\n\n## When WebP isn't the best target\n\nFor **transparent** PNGs (logos, icons), AVIF often keeps the alpha channel at a smaller size than WebP. assetopt can route by content — opaque → WebP, transparent → AVIF — automatically.\n\nThat's the whole loop: preview, convert, done — locally, no upload. If you want the full write-up (config reference, wiring it into a build step, the CI quality gate), it lives here:\n\n👉 **Convert JPG & PNG to WebP in bulk — the full guide**\n\nIf you give it a spin I'd genuinely like to hear what savings you get on your own assets — drop a comment.",
"title": "Convert a whole folder of images to WebP — locally, no upload, one command"
}