NNicheStackTutorials
← All tutorials
Static Hosting

Vercel Static Site Loaded in 6 Seconds — Images Were the Whole Problem

Performance audit on image-heavy tutorial blog. Lazy loading, responsive srcset, and moving off unoptimized PNGs cut LCP 74%.

·11 min read·Static Hosting
Vercel Static Site Loaded in 6 Seconds — Images Were the Whole Problem cover

Lighthouse mobile: LCP 6.2s, Performance 54 Hosting: Vercel (not the bottleneck — assets were)

Waterfall autopsy

hero.png     2.8 MB   4.1s   (no dimensions, no lazy)
step-1.png   1.9 MB   blocked by hero
step-2.png   1.7 MB

Six PNG screenshots above fold on every post.

Fix 1: width/height on every img

<img src="/images/hero.webp" width="1200" height="630" alt="..." fetchpriority="high">

Stops CLS. Browser reserves space before decode.

Fix 2: lazy below fold

<img src="/images/step-1.webp" width="800" height="450" loading="lazy" decoding="async" alt="...">

Fix 3: responsive srcset (static build)

Hugo example:

<img
  srcset="/images/hero-400.webp 400w, /images/hero-800.webp 800w"
  sizes="(max-width: 600px) 100vw, 800px"
  src="/images/hero-800.webp"
  width="800" height="420"
  alt="...">

Mobile downloads 400w (~45KB) not 1200w (~280KB).

Fix 4: don't use Vercel Image Optimization for static export

Requires Next.js or custom loader. For Hugo/Astro, optimize at build time, not request time.

Vercel-specific: enable compression

Brotli/gzip automatic for text. Images must be compressed before deploy.

Pre-deploy image audit script

// scripts/audit-images.mjs
import fs from 'node:fs';
import path from 'node:path';
function walk(dir) {
  for (const f of fs.readdirSync(dir, { withFileTypes: true })) {
    const p = path.join(dir, f.name);
    if (f.isDirectory()) walk(p);
    else if (/\.(png|jpe?g)$/i.test(f.name)) {
      const kb = fs.statSync(p).size / 1024;
      if (kb > 200) console.log(kb.toFixed(0) + ' KB', p);
    }
  }
}
walk('public/images');

Fail CI if any image > 200KB — catches regressions before they hit Vercel.

After

LCP: 6.2s → 1.6s
Total page weight: 9.1 MB → 420 KB
Performance score: 54 → 91

Vercel edge was fast all along — payload wasn't.

Tags: VercelPerformanceImagesLCP