Optimizing LCP on Astro with Priority Hints
Astro pre-renders HTML, so the hero image is usually present in the markup from the first byte. What still goes wrong is priority: the browser finds the hero alongside every other image and CSS request and gives it no special treatment, so it queues behind less important resources. Priority hints fix this by telling the browser which single resource matters most. This is the Astro-specific recipe for the discovery step in Largest Contentful Paint Optimization for Static Sites, within the broader Performance Optimization & Core Web Vitals for SSGs work.
Prerequisites
- An Astro project (v3 or later) using
astro:assetsfor images. If you have not set that up, start with Image Optimization Pipelines in Astro. - A deployed URL (a preview deploy is fine) so you can measure real headers and waterfalls — local dev does not reproduce edge timing.
- Lighthouse (or
lhci) and access to a WebPageTest run for the network waterfall.
The Recipe
1. Mark the hero with the priority prop
Astro's <Image> component ships a priority shorthand. Setting it flips three things at once: loading="eager", fetchpriority="high", and no lazy loading. Use it on the hero only:
---
import { Image } from 'astro:assets';
import hero from '../assets/hero.jpg';
---
<Image
src={hero}
alt="Product dashboard overview"
widths={[800, 1200]}
sizes="(max-width: 800px) 100vw, 1200px"
format="avif"
priority
/>
The rendered <img> carries fetchpriority="high" and loading="eager", so the browser fetches it ahead of the default-priority images it discovers later. Because <Image> also emits explicit width/height, it reserves layout space and avoids the shift that would otherwise hurt CLS.
2. Add a preload only when discovery is late
The priority prop does not emit a <link rel="preload">. If your hero is a CSS background-image, or rendered by a component that the preload scanner reaches late, add the preload by hand in the document head:
---
// src/layouts/Base.astro
---
<head>
<link rel="preload" as="image" href="/_astro/hero.HASH.avif"
fetchpriority="high" />
</head>
For a normal <Image priority> that the parser already finds at the top of the body, skip the preload — it would duplicate a request the browser is already prioritizing. Reach for it only when the network panel shows the hero starting late.
3. Keep priority exclusive
fetchpriority="high" is relative. If the logo, three feature thumbnails, and the hero are all high, the browser cannot tell which one to fetch first and the hint does nothing. Leave every non-LCP image at default (or loading="lazy" if below the fold) so the hero is the only high request on the page.
Measured Impact
Measured on a documentation landing page deployed to a CDN, throttled mobile profile (4x CPU, ~1.6 Mbps), median of five Lighthouse runs:
| Change | Hero request start | LCP | FCP |
|---|---|---|---|
Baseline (<Image>, no hints) | 910 ms | 2.7s | 1.9s |
+ priority (eager + fetchpriority) | 240 ms | 2.0s | 1.8s |
+ rel=preload (late-discovery hero) | 120 ms | 1.6s | 1.8s |
The hint moved the hero request from 910 ms to 240 ms after navigation start, and LCP fell from 2.7s to 2.0s. Adding the preload (this page's hero was set via CSS, so the scanner found it late) shaved another 0.4s to 1.6s. WebPageTest confirmed the hero moved to the front of the waterfall in both filmstrip and request log.
Pitfalls & Rollback
priorityon multiple images: the most common mistake. It dilutes the signal; one hero only.- Preload pointing at a stale hash: Astro fingerprints asset filenames, so a hard-coded preload URL breaks on the next build. Generate the URL from the imported asset or omit the preload and rely on
priority. - Preloading an off-screen image: preloading a resource that is not the LCP element wastes bandwidth and can delay the real LCP. Confirm with the Lighthouse LCP element audit.
- Rollback: removing the
priorityprop and any manual preload line reverts the behavior completely — there is no cache or build state to clear. Re-run Lighthouse to confirm you are back to baseline.
Conclusion
Priority hints are the cheapest LCP win available to an Astro site: one priority prop on the hero, and a rel=preload only when the hero is discovered late. On the example page they cut LCP from 2.7s to 1.6s without changing a single byte of the image. Pair them with format and sizing work in Reducing LCP from Hero Images on Static Sites and the render-delay fixes in Eliminating Render-Blocking CSS on Static Sites for the full LCP picture.
FAQ
What does the Astro Image priority prop actually do?
The priority prop on Astro's <Image> component sets loading to eager and fetchpriority to high, and skips lazy loading, in one shorthand. It does not emit a preload link, so for a CSS background or a late-discovered image you still add a manual rel=preload in the head.
Should I use fetchpriority high on more than one image?
No. Priority is relative, so marking several images high tells the browser they are all equally important and the benefit disappears. Reserve fetchpriority="high" for the single LCP element and let everything else load at default or lazy priority.
Do I need both a preload link and fetchpriority high?
Not always. If the hero is a normal <img> the preload scanner finds early, fetchpriority="high" alone is enough. Add a preload only when the resource is discovered late, such as a CSS background image, and then measure that it actually helped rather than wasted bandwidth.
How do I confirm the priority hint worked?
Run Lighthouse and check the LCP value and the "Largest Contentful Paint element" audit, and look at the network panel or a WebPageTest waterfall to confirm the hero request now starts near the top of the waterfall instead of behind other images.
Related
- Parent: Largest Contentful Paint Optimization for Static Sites — the full LCP workflow this fits into.
- Reducing LCP from Hero Images on Static Sites — sizing and format for the hero.
- Eliminating Render-Blocking CSS on Static Sites — cut the render-delay span.
- Image Optimization Pipelines in Astro — the
astro:assetssetup behind<Image>.