$263 of my vercel bill was image optimization, not compute Serverless Pricing
Marketplace site, user-uploaded photos, about 9,000 listings. Bill was $341 and I assumed it was function invocations because traffic doubled last month.
It was not. Functions were $34. Image optimization was $263.
I use the framework image component everywhere with a responsive sizes attribute, which as far as I can tell means each source image can be requested at eight different widths. Multiply by the quality variants and by 9,000 images that are all unique because users upload them, and the transformation count is enormous. These are not the same hero image served a million times, they are a million different images served once each.
What is the actual pattern for user-generated images here? I do not need magic, I need photos to load at a sensible size without paying more for resizing than for hosting.
@whetstone_wu · 4w ago · 3 replies
You have correctly identified the fundamental mismatch. Built-in image optimization is priced for a site with a few hundred distinct images requested many times. A marketplace has the opposite shape - many images, each requested a handful of times - so your cache hit rate on transformations is terrible by construction and you pay near full price for almost every one.
Three things, in order of effort:
Cut the variant count. Every unique combination of (source, width, quality) is a separate billable transformation. Trim
deviceSizesandimageSizesin your config to the widths you actually use, and pin quality to a single value. Going from 8 widths x 2 qualities to 3 widths x 1 quality is a 5x reduction for zero visible difference on a listing card.Raise the cache TTL. There is a minimum cache TTL setting and the default is lower than you want for content that never changes. A listing photo uploaded once and never edited should have a TTL measured in months. If the cached transform expires, the next request pays for it again.
Transform at upload, not at request. This is the real answer for UGC. When the user uploads, generate three sizes once, put them in object storage, store the URLs. Then serve them as plain images with
unoptimizedset. You pay for three transforms per listing ever, instead of per viewport per visitor. For 9,000 listings that is 27,000 operations total, once.Reply
Report
@egress_egon · 4w ago
Transform-on-upload is obviously right for my case and I think I avoided it because it means a queue and a worker. Which, fine, that is an afternoon and it is $263 a month.
Reply
Report
@packlist_pen · 4w ago
You may not even need a queue. Do it inline in the upload handler with a decent image library - resizing a photo to three widths is a couple hundred milliseconds. Only move it to a queue when the upload latency starts bothering people, or when you add a format conversion that is genuinely slow.
Reply
Report