Open the network panel on almost any content site, sort by size, and the top of the list is pictures. Not the framework. Not the fonts. The hero image, the product shots, the avatars in the comments. This has been true for most of the web's history and it is still true now, which is worth saying plainly because a great deal of performance effort goes somewhere else first.

The HTTP Archive has tracked page composition for years, and images have consistently been the largest single category of bytes on the median page. You do not need to take a number on faith, though — open your own site and look. The answer is usually obvious within about ten seconds, and it is yours rather than an industry average.

Three changes, in the order that pays

Image work has a clear hierarchy of return. In rough order of bytes saved per hour spent:

1. Stop sending pixels nobody sees

The single biggest waste is dimensional. A 3000×2000 photograph displayed in a 600px column is carrying about twenty-five times the pixel data it can possibly show. No format, no compression setting, and no CDN fixes that — the file is simply larger than the job.

Resizing is unglamorous and it beats everything else on this list. If you do one thing, serve each image close to the size it is displayed at.

2. Use a modern format

JPEG is thirty years old and it shows. WebP and AVIF both encode the same image in substantially fewer bytes at comparable visual quality — AVIF more aggressively than WebP, and both more than JPEG. The exact ratio depends entirely on the image: a photograph of foliage and a flat illustration compress nothing alike, which is why a single headline percentage is nearly always somebody's best case rather than yours.

Measure it on your own library. Take twenty representative images, encode each three ways, and compare the totals. That number is real and it is the one you can plan against.

3. Turn the quality dial down further than feels comfortable

Quality settings are not linear and they are not perceptual. The difference between q=95 and q=80 is usually invisible on a photograph at display size and can be a large fraction of the file. The difference between q=80 and q=60 is often visible, but only on flat gradients and text.

The practical approach: pick a value, look at your ten worst-case images at full size, and move it until one of them bothers you. Then go back one step. Most teams land somewhere around the seventies and never touch it again.

What a proxy changes

None of the above requires a CDN. You can resize and re-encode at build time and ship the results, and for a small, fixed set of images that is a perfectly good answer with fewer moving parts.

A transforming proxy earns its place when the set is not fixed: user-uploaded content, a catalogue that changes daily, a design system whose breakpoints move. Then the alternative is a build step that has to know every size in advance and re-run whenever either the images or the layout change.

<!-- one original at the origin, three renditions on demand -->
<img src="https://…/v1/products/chair.jpg?w=800&f=auto&q=78"
     alt="Oak dining chair">

The transformation happens once per distinct URL and is cached at the edge afterwards. Which leads directly to the thing most teams underestimate — how many distinct URLs they have just created. That is its own article.

What this does not fix

Being honest about the boundaries:

  • Layout shift. Smaller images still reflow the page if you have not set width and height attributes. That is markup, not bytes.
  • Too many requests. Forty small images is still forty round trips. Lazy loading below the fold does more for that than compression does.
  • The wrong image entirely. A decorative 500 KB background that carries no information is best deleted, not optimised.

Optimisation is what you do to images you have decided to keep. Deciding what to keep comes first, and it is usually the larger win.