Demo, all content is generated
Question

Photo gallery burned through my Vercel image optimization quota in a week

Solved · 912 views · asked by lotte_j · edited

My photography portfolio (v0, Next.js, Hobby plan) got an email from Vercel that I'm over the image optimization limit. It's maybe 400 photos. Traffic went up after a Reddit post, but still. What counts as an image here and how do I stop it?

What I’ve tried

Looked at Usage in the dashboard: image transformations is the red one. Searched the code, every photo uses <Image> with fill.

Comment
Do you use sizes on the Image tags? sarah_k_dev · edited

4 answers

Marked as helpful by the asker
deploydan · edited

It's not "400 images", it's every image × width × format combination that gets generated. With fill and no sizes, the browser can ask for many widths, and each is a separate transformation.

What I'd do:

  1. Add a real sizes prop to every gallery image (e.g. sizes="(max-width: 768px) 100vw, 33vw"), so fewer widths are requested.
  2. Trim images.deviceSizes / imageSizes in next.config to the 3-4 widths your layout actually uses.
  3. Raise images.minimumCacheTTL (photos never change), so cached results are reused instead of regenerated.
  4. For the originals: export them as WebP at 2 sizes yourself and use unoptimized on those. Photographers care about quality anyway, you control the compression.

The Reddit spike will pass, but #1 and #3 alone usually cut this a lot.

Comment
sizes was missing everywhere (v0 never added it). Did 1-3, usage this week is a fraction of last week. lotte_j · edited
And sizes also makes the page faster on phones, so it's a win twice. bea_quinn · edited
wes_codes · edited

Alternative if the portfolio grows: put the photos on a storage/CDN with its own image resizing (Cloudinary, Supabase transformations, Cloudflare Images) and use a custom loader. You move the cost, but some of those have more generous free tiers for this use.

Comment
sarah_k_dev · edited

Also check that bots aren't requesting random widths. Every distinct w= parameter on /_next/image is a new transformation, and scrapers do hit those URLs directly.

Comment
aiko_n · edited

Small bonus for galleries: placeholder="blur" with static imports, or a tiny dominant-color background for remote images. The page feels faster while the photos load.

Comment