Optimize your assets at build time, not on every request
Most of a site’s assets are known long before a single visitor shows up. The hero image, the icons, the bundled CSS, the fonts: they live in your repo, and they are identical from one request to the next. There are only two places to optimize them. Once, when you build. Or over and over, at the edge, every time a page loads.
For the assets you ship yourself, building is the better place.
Why build time
You do the work once. The output is small the moment it ships and stays small, with no per-request CPU, no transform cache to warm, and no on-the-fly transform bill that grows with your traffic.
The result is also something you can see. The optimized files are right there in your build output, so you can diff them, weigh them, and know exactly what is going out. An edge transform is a black box you trust; a build artifact is a file you can open.
And it covers more than images. Your build already handles JavaScript, CSS, SVG and fonts, and all of those shrink too. A raw TTF shipped instead of WOFF2 is about two thirds wasted on its own.
Where the edge still earns its place
Build-time optimization only touches the assets that go through your build. Two cases genuinely need the request path:
- User uploads. If people upload images while your site is running, you can’t optimize those at build. That needs something on the request path: an API, or a CMS plugin.
- Huge, varied catalogs that need per-device sizing. If you truly serve a different size per device across millions of images, an on-the-fly service pays for itself.
For a normal site, which is most sites, neither of those is the bottleneck, and build time is simpler and cheaper.
Doing it
Two ways, both running on the Patu API so the encoding happens off your machine.
One command, in any build script or CI job:
PATU_KEY=your_key npx @patu.dev/cli ./dist
It walks the folder, optimizes the images, SVG, JS, CSS and fonts in place, and skips anything it can’t actually beat. Add --cdn to upload them and rewrite the references to cdn.patu.dev instead of writing back to disk.
Or wire it into Vite, so every build is covered without you thinking about it:
import patu from '@patu.dev/vite'
export default { plugins: [patu()] }
The point
The edge is not wrong. But there’s a good chance you are paying to transform, on every single request, assets that never change between them. Optimize them once, in the build you already run, and ship them small. The integrations page has the CLI, the Vite plugin, and the rest.