DEV Community

Nathmaxx
Nathmaxx

Posted on

Convert a whole folder of images to WebP — locally, no upload, one command

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.

It 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.

So 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.

Why WebP at all

WebP 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.

Install

npm install -g @assetopt/cli
Enter fullscreen mode Exit fullscreen mode

Or run it once, without installing anything:

npx @assetopt/cli --help
Enter fullscreen mode Exit fullscreen mode

The one-command version

Point 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.

Create a .assetoptrc that routes both source formats to WebP:

{
  "images": {
    "formatMatrix": { "jpeg": "webp", "png": "webp" },
    "quality": { "webp": 82 }
  },
  "output": { "dir": "./optimized" }
}
Enter fullscreen mode Exit fullscreen mode

Then convert the folder:

assetopt optimize ./images
Enter fullscreen mode Exit fullscreen mode

Every .jpg and .png under ./images is written as .webp into ./optimized, mirroring the source tree. Your originals stay exactly where they are.

Preview the savings before touching your disk

This is the part I actually use the most. analyze reports the exact before/after sizes as a dry run — it writes nothing:

assetopt analyze ./images
Enter fullscreen mode Exit fullscreen mode

You get a per-file table and a total. When the numbers look right, swap analyze for optimize.

Tune the quality, fast

WebP quality is a 1–100 dial (default 82). Lower means smaller files and more visible artifacts:

{ "images": { "formatMatrix": { "jpeg": "webp", "png": "webp" }, "quality": { "webp": 75 } } }
Enter fullscreen mode Exit fullscreen mode

Re-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.

Real numbers

Running the config above on a sample pack (JPG/PNG → WebP):

Source Before After (WebP) Saved
Large PNG export (opaque photo) 5.42 MB 552 KB −89.8%
JPEG photo 1.74 MB 1.44 MB −17.4%

The 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.

When WebP isn't the best target

For 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.


That'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:

👉 Convert JPG & PNG to WebP in bulk — the full guide

If you give it a spin I'd genuinely like to hear what savings you get on your own assets — drop a comment.

Top comments (0)