Back to blog
Ontwikkeling12 min

Next.js static export en Core Web Vitals: het 2026 playbook

TL;DR

Om 95+ PageSpeed mobiel op Next.js static export te halen: self-host fonts via raw @font-face, preload de LCP-font met fetchPriority=high, vermijd Framer Motion above-the-fold, gebruik alleen transform/opacity voor animaties, reserveer layout-ruimte voor i18n-content, serveer via Cloudflare free tier.

Julien Daniel
ByJulien Daniel
Founder & CTO, OptionWeb
Share
PageSpeed Insights dashboard met hoge prestatiescores

Na 12 maanden productiedata op 40+ Next.js sites met static export, hier het exacte playbook dat we toepassen om 95+ PageSpeed mobiel te halen. Geen theorie — alleen wat meetbaar werkt.

Baseline: wat static export je gratis geeft

Een vanilla Next.js static export site scoort 95-100 mobiel omdat alle HTML pre-rendered is, lage TTFB, geen cold starts, automatische code splitting. Zodra je Framer Motion, Google Fonts, iconen, analytics toevoegt, daal je naar 70-85 zonder het te beseffen.

LCP: de strijd tegen render-blocking CSS

PageSpeed-rapporten tonen hetzelfde probleem: twee render-blocking CSS-bestanden (Tailwind + next/font Google) voegen ~500ms render delay toe op mobile throttled. Dat is 100% van het LCP-budget.

styles/globals.csscss
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url('/fonts/space-grotesk-latin.woff2') format('woff2');
}

Font-strategie die echt werkt

  • Display font (headings) — 1 variable font via raw @font-face, range 500-700, preload fetchPriority=high.
  • Body font — next/font/google Inter met 2 weights (400, 600), alleen latin.
  • Monospace — next/font/google JetBrains Mono, 1 weight, preload=false.

INP: Framer Motion valkuilen

INP verving FID maart 2024, veel strikter. Boven 200ms = 'poor'. Framer Motion vaak de schuldige.

tsx
// ❌ Slecht: vertraagt LCP
<motion.h1 initial={{ opacity: 0 }} animate={{ opacity: 1 }}>Titel</motion.h1>

// ✅ Goed: CSS keyframe, geen JS-vertraging
<h1 className="ow-anim-fade-up">Titel</h1>

Regels: nooit width/height/top/left animeren (layout reflow). Alleen transform/opacity. Max 1-2 animaties per viewport. Altijd useReducedMotion gebruiken.

CLS: i18n-reserveringspatroon

Op i18n-sites verschijnt CLS wanneer vertalingen laden na initial render. Oplossing: reserveer min-height per breakpoint.

tsx
<div className="min-h-[280px] sm:min-h-[220px] md:min-h-[160px] lg:min-h-[130px]">
  <p>{t('tldr.content')}</p>
</div>

Afbeeldingen: AVIF, priority, fetchPriority

next.config.jsjs
images: {
  unoptimized: true,
  formats: ['image/avif', 'image/webp'],
}

Hosting: Brotli 11, HTTP/3, Early Hints

  1. Origin host — elke statische host.
  2. Cloudflare free tier vooraan — HTTP/3, Brotli 11, edge cache.
  3. Early Hints (103) — elimineert TTFB wait van critical path.
  4. Cache rule _next/static/* — Cache Everything, Edge TTL 1 jaar.
  5. Purge cache on deploy — wrangler of Cloudflare API in CI.

Hoe PageSpeed regressie debuggen

  1. Vergelijk PageSpeed rapporten — welke metriek is gedaald.
  2. Critical request chain — wat blokkeert nu het renderen.
  3. Chrome DevTools Performance — localhost met throttling.
  4. Git diff deps — nieuw npm package?
  5. Check next build output — route +20KB = verdacht.
Tags#nextjs#performance#core-web-vitals#pagespeed#framer-motion