# Vercel Image Bills Burned Us: Cut Them 80%

> next/image transforms meter per variant on Vercel. AVIF, responsive sizes, long TTLs, and edge caching cut the line 80%. The playbook inside.

Source: https://boringpush.com/blog/vercel-image-optimization-bill-cut

## The image bill bigger than hosting
A photography-heavy marketplace: 2,000 product images, responsive `next/image` everywhere, decent traffic. Month's end: the Image Optimization line alone beats the old VPS bill — transforms in the millions, cache writes stacking, each variant billed like a tiny deployment.

Nobody approved this. Developers used the documented component correctly. The meter priced each correctness separately: per source image, per width variant, per format negotiation, plus cache read/write operations underneath.

Vercel image optimization bill pain is the meter most teams discover last because images feel free — they're just files. On metered transforms, they're tiny invoices wearing file clothes.

## Where image money actually goes
| Source | What meters | Typical multiplier |
|---|---|---|
| Width variants | Transform per size | 5–8x per upload |
| Format negotiation | AVIF/WebP per variant | 2x on top |
| Cache writes | First-gen per variant | 1x, then reads |
| Cache reads | Every served variant | Ongoing per view |
| Source allowance | ~5k images on Pro (verify) | Over-quota per thousand |

Three details multiply the damage:

1. **Responsive markup multiplies uploads.** `sizes` with six breakpoints turns one product photo into six transforms minimum — times two formats, times cache operations. A 2,000-image catalog becomes 24,000+ metered units before a single visitor arrives. Pre-generation at build time doesn't help; it just front-loads the bill.
2. **Unoptimized uploads compound.** A 8MB camera original transforms slower and bigger than a 200KB pre-compressed input — same visual result, multiples of meter. Every byte uploaded raw gets transformed, cached, and served at premium size. Compression belongs at upload, not at edge.
3. **Short TTLs re-bill served images.** Default cache lifetimes revalidate variants constantly, turning one-time transforms into recurring reads. Year-long immutable caching (hashed filenames) converts repeat views to $0 — the single highest-leverage line in this post.

The $1,800-exit post named images the silent killer. This one defuses them.

## Vercel image optimization bill cut
In-platform first (stay), flat-hardware escape second (when meters persist).

**Step 1 — Shrink inputs before they meter.**

```js next.config.js
images: {
  formats: ["image/avif", "image/webp"],   // modern first, smallest bytes
  deviceSizes: [640, 1080, 1920],          // 3 widths, not 8 (audit your CSS)
  imageSizes: [64, 128, 256],              // icons small, deliberate
  minimumCacheTTL: 31536000,               // immutable: cache for a year
},
// upload pipeline: compress to <300KB + strip EXIF before storage, always
```

Three widths cover real layouts (audit breakpoints — most sites use three, declare eight). AVIF-first halves bytes over JPEG at equal quality. Pre-compressed inputs mean transforms process kilobytes, not megabytes. Input discipline cuts the meter at its root: fewer, smaller source operations.

**Step 2 — Cache like the bill depends on it (it does).**

```text
filenames: content-hashed (app-3f9a2c.avif) → immutable forever
headers: Cache-Control: public, max-age=31536000, immutable
edge: Cloudflare in front caches variants globally (origin transform once)
```

Hashed filenames make immutability safe (changed image = new hash = new URL, zero staleness). Year-long headers stop revalidation churn. Edge caching converts the origin transform into a one-time event per variant globally — subsequent views worldwide cost nobody anything. Cache architecture is billing architecture wearing a performance costume.

**Step 3 — Move serving flat when transforms dominate.**

```bash
# same images, $5 VPS: Nginx serves pre-built variants from disk
# build-time script generates 3 widths × AVIF/WebP once (local CPU, $0)
# Cloudflare caches globally; origin meter: none exists
# trigger: image line past ~$100/mo sustained → the weekend migration pays back in weeks
```

Pre-generated variants on disk plus edge cache equals the transform pipeline with zero per-unit meter. The $100/mo image-line threshold is the honest trigger — below it, optimize in place (steps 1–2 recover most); past it, flat serving's payback window is weeks. Meters deserve exits, not just efficiency.

It all holds together — pixels without per-variant invoices.

## The image-line diet
| Measure | Before | After steps 1–2 |
|---|---|---|
| Variants per upload | ~16 (8 widths × 2 formats) | 6 (3 × 2) |
| Avg source size | 2–8MB camera raw | <300KB compressed |
| Cache lifetime | Default (revalidating) | 1 year immutable |
| Repeat-view cost | Metered reads | $0 (edge hits) |
| Total image line | Baseline $$$$ | ~20% of baseline |

Worth saying plainly: fewer widths risk edge-case layouts (audit CSS first, add back widths with evidence), AVIF encoding costs build CPU (pennies locally, meters remotely — hence flat), and immutable caching demands hashed-filename discipline (forget once, serve stale faces for a year).

BoringPush prices discipline against meters: filename hygiene is free, transforms are forever. Cheap rigor, expensive laxity.

## FAQ

### Does vercel image optimization bill cut work without leaving Vercel?
Yes — steps 1–2 are platform-native and recover ~80% regardless of host. Leaving (step 3) is for sustained high-volume lines past ~$100/mo, where per-unit economics beat any optimization. Optimize first everywhere (weeks of runway), exit second only on proof. Most image bills die at step 2; step 3 exists for catalogs, not blogs.

### Should I use a dedicated image CDN (Cloudinary, Imgix) instead?
Same meter, different logo: per-transform pricing with better tooling and worse lock-in (URLs embed vendor syntax across your content). Dedicated CDNs win on transformation features (cropping APIs, art direction); they lose on the same unit economics plus migration friction. Self-serve variants plus edge cache match 90% of needs at flat cost. Features you use justify vendors; features you admire don't.

### How do user-uploaded avatars fit the pre-compression rule?
Compress client-side before upload (browser Canvas API → <100KB WebP) plus server-side validation (dimensions, type, size caps). Avatars are the highest-volume untrusted input — uncompressed 5MB selfies from phones are the classic meter bomb. Client compression is UX (fast uploads) plus billing (small transforms) in one line of code. Never accept raw camera bytes from users.

### What about `next/image` placeholders (blur) — do they meter?
Blur placeholders generate tiny transforms (negligible) but the `blurDataURL` build-time generation adds build minutes on large catalogs. Static imports handle it at build; remote images need explicit blur data or the shimmer fallback. Placeholder cost rounds to zero against variant math — optimize variants first, admire placeholders later (they're free-ish either way).

### Can I pre-generate variants at build time on Vercel?
Technically yes, economically pointless: build-time generation still consumes build minutes and cache writes on metered infrastructure. Pre-generation pays on flat hardware (local CPU, $0 marginal) and costs on meters. Match the optimization to the host: lean configs on Vercel, pre-generation on VPS. Right trick, wrong host is still wrong.

### When do images justify the VPS move alone?
Sustained image line past ~$100/mo with catalog growth (marketplaces, UGC, photography) — payback in weeks, plus the bandwidth and request meters fall in the same migration. Single-meter exits are rare; image-heavy apps usually drag bandwidth along (the $1,800 anatomy shows the bundle). Migrate on the bundle math, credit images as the trigger.

## Keep reading

- [Vercel's 100GB Limit Dies on Day 13 (Do This)](/blog/vercel-bandwidth-100gb-limit-overage) — the sibling meter, same playbook shape
- [We Left Vercel at $1,800/mo for a $5 VPS](/blog/vercel-1800-month-to-5-vps) — the exit this diet postpones or justifies
- [$900 Vercel Bill? How Surprise Invoices Happen](/blog/vercel-surprise-bill-900-fix) — all four meters, one invoice
