An image budget that fails the build
Large images creep into apps one pull request at a time. A small script that runs before every build stops them at the door.
Images are the easiest way to make a fast app slow. Nobody adds a 1.8 MB PNG on purpose. It arrives as a “quick banner” or a screenshot that was meant to be temporary, one pull request at a time. Reviews rarely catch it, because a diff shows a binary file, not its weight.
In the new apps I worked on, we made the build catch it instead.
The budget script
A short Node script runs before every build (prebuild in package.json). It walks the image folders, checks each file’s size against a budget, and fails the build with a clear message if anything is over. Something like this (the numbers here are illustrative):
✕ public/banners/launch.png is 1.84 MB (budget 300 KB).
Run `npm run images:optimize` or move it to the CDN.
Failing the build sounds harsh, but it’s the kindest place to find out: on your own machine or in CI, minutes after you added the file, rather than months later in a performance review.
Make the right thing easy
A budget on its own is just a gate. Two things made it pleasant to live with:
- An optimise script that compresses images in place, so fixing the error is one command.
- Static imports for images, so the framework knows each image’s dimensions at build time. That means it can reserve space for the image (no layout shift) and serve sized versions. A lint rule nudges people toward the shared image component instead of a raw
<img>.
Where the numbers come from
Pick budgets from the job the image does. A logo or icon should be tiny. A full-width banner can be bigger. Photos should be served in modern formats at the size they’re displayed. Start strict, and loosen a budget only with a reason written next to it.
The result
The rule, the script and the reasoning live in the project’s conventions file, so new contributors (and AI coding agents) learn them on day one. Since then, image weight has been something the build reports, not something someone has to remember.