Many developers assume that moving to a static architecture automatically means a perfect performance score. In my experience, that’s a dangerous assumption. While the server-side latency is gone, client-side bottlenecks—like oversized JS bundles and unoptimized images—can still tank your rankings. Optimizing Core Web Vitals for JAMstack isn’t about a single ‘magic button’; it’s about a series of targeted refinements to how your browser renders content.
Whether you’re debating Astro vs Next.js for static sites or you’ve already deployed your project, the goal remains the same: a seamless, instant user experience. In this tutorial, I’ll walk you through the exact workflow I use to hit those elusive 100s in PageSpeed Insights.
Prerequisites
- A deployed JAMstack site (Next.js, Astro, Hugo, or Gatsby).
- Basic familiarity with Chrome DevTools and the Lighthouse tab.
- Access to a CDN (Vercel, Netlify, or Cloudflare Pages).
- A basic understanding of JAMstack architecture best practices.
Step 1: Eliminating LCP (Largest Contentful Paint) Bottlenecks
LCP measures how long it takes for the largest visible element to render. In most JAMstack sites, this is the hero image or a large H1 heading. If your hero image is being lazy-loaded, you’re actively hurting your LCP.
Prioritize the Hero Image
I’ve found that adding a fetchpriority="high" attribute to the LCP image is the fastest way to see a gain. Here is how I implement it in a modern React/Next.js environment:
<!-- Avoid lazy loading for the LCP element -->
<img
src="/hero-banner.webp"
alt="Product Showcase"
fetchpriority="high"
loading="eager"
width="1200"
height="600"
/>
Optimize Image Formats
Stop using JPEGs for everything. Move to WebP or AVIF. If you are using a framework like Astro, I highly recommend their built-in image component which handles this automatically at build time.
Step 2: Reducing CLS (Cumulative Layout Shift)
CLS is that annoying jump that happens when an image loads and pushes the text down. It’s a primary reason for poor user experience scores.
Set Explicit Dimensions
Never let the browser guess the size of your images. Always provide width and height attributes. This allows the browser to reserve the space before the asset actually downloads.
Manage Dynamic Content and Fonts
Web fonts are a common source of CLS. When a custom font loads, it often replaces a system font with a different width, causing a “flash of unstyled text” (FOUT). To fix this, use font-display: swap; in your CSS, or better yet, use a tool like Next/font to self-host your fonts.
As shown in the technical diagram below, the flow of resource loading significantly impacts how the browser calculates layout stability. If you want to know if JAMstack is still worth it in 2026, the answer is yes—specifically because of how much control we have over these rendering paths.
Step 3: Improving Interaction to Next Paint (INP)
INP has replaced FID as a primary metric. It measures the overall responsiveness of the page. In JAMstack, the biggest killer of INP is “Hydration Overload”—where the browser is so busy turning static HTML into a reactive app that it ignores user clicks.
Implement Partial Hydration (Islands Architecture)
If you have a massive page but only the search bar is interactive, why hydrate the whole page? This is where the “Islands Architecture” shines. By only hydrating the components that need it, you free up the main thread.
<!-- Example: Astro component approach -->
<!-- This component renders as static HTML (Zero JS) -->
<StaticHeader />
<!-- This component is hydrated only when it enters the viewport -->
<InteractiveCart client:visible />
Pro Tips for Advanced Optimization
- Speculative Loading: Use
<link rel="prefetch">for the most likely next page the user will visit. - CSS Inlining: For critical above-the-fold styles, inline the CSS directly in the
<head>to avoid an extra network round trip. - Edge Middleware: Use Edge functions to handle redirects and geolocation at the CDN level rather than on the client side.
Troubleshooting Common Issues
“My Lighthouse score is great on desktop but poor on mobile”
This is usually due to CPU throttling. Mobile devices process JavaScript much slower than your M3 MacBook. Test your site using “Applied Throttling” in Chrome DevTools to see the real-world experience of a user on a mid-range Android device.
“Images are still shifting despite having dimensions”
Check if you have CSS like width: 100%; height: auto; without a wrapping container that has a defined aspect ratio. Use the CSS aspect-ratio property to maintain the box size.
What’s Next?
Once you’ve mastered optimizing Core Web Vitals for JAMstack, the next step is implementing a continuous monitoring system. I recommend setting up CrUX (Chrome User Experience Report) monitoring to see how real users—not just synthetic bots—are experiencing your site.
Ready to scale your performance? Check out my other guides on JAMstack architecture best practices to ensure your site remains fast as it grows.