THE IMAGE PIPELINE
The FAL plus Sharp pipeline I run on every Seahawk site to hit Lighthouse 100 image scores by default, with concrete file-size numbers.
Why image discipline is half the performance battle
Images are the LCP element on roughly 70 percent of marketing pages. Image discipline is the single highest-leverage performance lever I know. The teams that get this right hit Core Web Vitals effortlessly; the teams that get it wrong fight Core Web Vitals forever.
The discipline is structural: pick the format, resize at upload time, optimise the encoding, set explicit dimensions, preload the LCP image. Each one of those is a one-time engineering investment that pays back across every page on every site.
FAL hero generation
I generate hero images via FAL flux-pro/v1.1-ultra and Recraft v3. Both produce 1200 by 675 pixel JPEGs at full encoding quality, typically 600KB to 1.5MB per image. Uploading raw to Supabase Storage means every page ships ~1MB of hero alone.
FAL costs roughly 4 cents per hero image, which is negligible compared to manual photography or stock licensing.
Sharp re-encoding to WebP
Before any upload, the image goes through sharp(buf).resize({width:1600, fit:"inside"}).webp({quality:82}).toBuffer(). This produces a WebP file 90 percent smaller than the source JPEG with no perceptual loss. A 900KB hero becomes an 80KB hero.
Across 53 hero images on gautamkhorana.com, the total saving was roughly 50MB site-wide. The same pipeline applied to client sites at Seahawk consistently delivers similar gains. The code is ten lines; the impact is durable.
Storage upload settings
Set cacheControl: 31536000 on the storage upload so the CDN caches the file for a year. WebP format gives modern browsers what they want; older browsers fall back to JPEG via the picture element.
Use a stable URL pattern (slug-hero.webp) so the cache invalidation story is clean. When a hero updates, the slug should rotate (slug-hero-v2.webp) and the database updates the URL atomically.
The frontend integration
Every hero image must have explicit width and height attributes in the HTML. Without them, layout shifts as the image loads and CLS rises. Astro and Next.js Image components handle this automatically; raw img tags need it manually.
The above-the-fold hero image must be preloaded with link rel="preload" as="image" in the document head. Saves 100 to 400 milliseconds typically on the LCP metric. Single highest-impact one-line change available on most marketing sites.
Lazy-load every image below the fold with loading="lazy". Browsers handle this natively now; no JavaScript library needed.
The full pipeline in one helper
I extracted this pipeline into scripts/lib/optimize-image.mjs which takes a buffer, runs the resize plus WebP encode, returns the optimised buffer. Used across the auto-blog hero pipeline, the bulk re-encoding scripts, and the manual-upload utility.
The single helper means the discipline is centralised. New scripts that need to upload images call the same helper, get the same compression, produce the same file sizes. The discipline does not depend on any single engineer remembering to run sharp.
WHEN YOU ARE READY TO TALK
If you are mid-build on something this guide touches and want a second pair of eyes, the fastest path is a 30-minute call.
BOOK YOUR 30-MIN CALL