Bloat the visitor never sees
Plenty gets written about slow load times caused by images — rightly so. What comes up less often is the other half of the equation: an unoptimized image doesn't just burden the visitor's browser, it stays — in the file system, in the CMS, in every backup, in the version history, in every deploy pipeline. Nobody sees these costs in the frontend, and that's exactly why they keep growing unchecked for so long.
As a starting point I'll take the figure from my worked example on website size: 1,200 pages, 3 images each at an average of 3 MB, which comes to roughly 10.8 GB of raw original images. Let's follow what becomes of that behind the scenes.
The media library nobody cleans up
No CMS stores just the original. WordPress, TYPO3, shop systems — on every upload they automatically generate several image sizes: thumbnail, medium, large, often format and retina variants on top. In practice, each original image quickly racks up two to three times its size in derived files. That easily turns 10.8 GB of originals into a 25–30 GB media library — and it's practically never cleaned up. Deleted posts, swapped-out images, test uploads: they linger as orphaned files because nobody notices them in the frontend.
Backups multiply everything
Now comes the multiplier that turns a nuisance into a real cost problem: backups. A proper backup strategy keeps several restore points on hand — say, 30 daily full backups. Each one contains the complete, unoptimized media library:
| Item | Unoptimized | Optimized |
|---|---|---|
| Original images | ≈ 10.8 GB | ≈ 0.7 GB |
| + CMS sizes (×2–3) | ≈ 20 GB | ≈ 1.3 GB |
| = Media library | ≈ 30 GB | ≈ 2 GB |
| × 30 daily backups | ≈ 900 GB | ≈ 60 GB |
Nearly a terabyte of backup storage — for a website whose meaningful image content fits in 2 GB. The difference isn't theoretical: it shows up on the backup-storage bill, drags out every restore, and turns a quick "just roll it back" into an hour-long chore.
Deploy, build, and repository
In modern projects — static-site generators, JAMstack, Git-based workflows — images often land straight in the repository. That backfires twice over. First, on every deploy the build has to copy, process, and upload gigabytes of images; a 30-second build turns into a multi-minute marathon. Second, Git stores every version of every binary file forever — swap out a 4 MB image three times and all four versions sit permanently in the history. Once a repository has filled up with unoptimized images, the only way to slim it down again is an invasive history rewrite.
The bandwidth line item
And then there's the ongoing traffic. As shown in the worked example, at realistic visitor numbers this adds up to over a terabyte of outbound image traffic per month — versus roughly 72 GB in the optimized case. With any CDN that bills for egress, that's a recurring line item that grows linearly with the site's success. Precisely when a site is doing well, the bloat becomes most expensive.
The friction on the team
The last, often underestimated cost is time. A repository with many gigabytes of images clones slowly, the local dev server starts sluggishly, and every new colleague waits through that first checkout. None of it is dramatic on its own — but taken together it wears a little off every working day. Lean projects feel faster not just for visitors, but for the people working on them.
Where to start
The most effective rule is the simplest: images get optimized before they enter the system, not after. If the original is uploaded at the right size and in a modern format from the start, every derived version, backup, and repository entry comes out lean from the outset. Concretely:
- Prep before uploading: resize to the target dimensions, convert to WebP/AVIF, and compress — with JNRT Pixel locally in the browser, no upload.
- Keep binary files out of the Git repo and serve them instead via media storage or a CDN.
- Declutter the media library regularly — orphaned uploads and old variants cost backup storage without ever being served.
Load time is the visible part of the problem; the storage behind the scenes is the invisible one. Both stem from the same cause — and both can be avoided with the same single move at the start of the chain.
Sources
HTTP Archive — Web Almanac, Page Weight · web.dev — Serve images in modern formats · Pro Git — Git Internals: Packfiles · MDN — Image file type and format guide.