Tags: web-dev concept

Priority Hints

Date: 2026-08-17


The fetchpriority attribute, for telling the browser a resource matters more or less than its heuristics assume. It’s a small, precise tool — unlike Resource Hints it doesn’t start work earlier, it only reorders work the browser was already going to do.


Priority hints are the fetchpriority attribute (high, low, auto) on images, scripts, links and fetch() calls, adjusting the priority the browser assigns a resource it has already discovered.

The distinction from resource hints

RESOURCE HINTS                       PRIORITY HINTS

"start this EARLIER than you         "you already know about this —
 would have discovered it"            fetch it SOONER or LATER than
                                      you planned"

changes WHEN discovery happens       changes the ORDER of a known queue
costs a whole extra request          costs nothing

Priority hints are free. They don’t add a request; they change where an existing one sits in the queue. That makes them much safer to use than preload, and the right first thing to try when the browser’s ordering is wrong.

The browser’s default priorities

Worth knowing, because the hint is a correction to these:

Highest    HTML, CSS in <head>, fonts discovered in CSS
High       scripts in <head> (blocking), XHR/fetch
           images IN THE VIEWPORT — but only once layout says so
Low        images below the fold, async/defer scripts
Lowest     prefetch, images with loading="lazy"

The problem this solves is the “but only once layout says so” line. The browser can’t know an image is in the viewport until it has enough CSS and layout to place it — so the hero image on a retail page often starts at Low priority and gets upgraded a few hundred milliseconds later, after the moment that mattered.

The syntax

<!-- the LCP image: promote it above the other images -->
<img src="/hero.avif" fetchpriority="high" alt="…">
 
<!-- a carousel: first slide matters, the rest don't -->
<img src="/slide-1.avif" fetchpriority="high" alt="…">
<img src="/slide-2.avif" fetchpriority="low" loading="lazy" alt="…">
<img src="/slide-3.avif" fetchpriority="low" loading="lazy" alt="…">
 
<!-- demote a script that doesn't affect the first screen -->
<script src="/reviews-widget.js" defer fetchpriority="low"></script>
 
<!-- works on fetch() too -->
fetch('/api/recommendations', { priority: 'low' });

Three values: high, low, and auto (the default, meaning “use your heuristics”).

Where it earns its place

Promoting the LCP image — the main use, and the one with a measurable effect on a retail product or category page.

product page, hero image below a nav and a promo bar

without fetchpriority
  HTML parsed          → image discovered, priority Low
  CSS downloaded       → layout computed
  image now known
    to be in viewport  → priority raised to High
  fetch begins          ← ~250ms later than it could have
  LCP                  2.9s

with fetchpriority="high"
  HTML parsed          → image discovered, priority High immediately
  fetch begins
  LCP                  2.6s

Demoting what competes with it is the other half, and it’s the half people skip. Promoting everything achieves nothing — the gain comes from the gap between the hero image and the carousel slides, the below-fold images and the non-critical scripts.

Demoting a third-party script so the tag manager or chat widget stops competing with content for bandwidth during the initial load — Third-Party Scripts, Tag Manager Performance.

Where it doesn’t help

  • When the resource isn’t discovered yet. Priority can’t reorder something the browser hasn’t found. A font referenced from CSS needs preload, not fetchpriority — Resource Hints
  • When bandwidth isn’t the constraint. On a fast connection with few resources, everything arrives quickly regardless and reordering changes nothing. The gains concentrate on mobile and constrained connections, which is where they matter most and where you’re least likely to notice them locally — Field vs Lab Data
  • When the real problem is the number of resources. Reordering forty requests is worse than having fifteen — The Critical Rendering Path
  • On a slow server. No client-side prioritisation helps if the first byte takes 1.4 seconds — Time to First Byte

The traps

  • fetchpriority="high" with loading="lazy" on the same image — contradictory, and the lazy attribute effectively wins. This is a common accident when a component sets one and a wrapper sets the other
  • Promoting more than one or two things. If three images are high priority, none of them is
  • Forgetting it on responsive <picture> sources. The attribute goes on the <img>, not the <source>
  • Assuming it’s a guarantee. It’s a hint. The browser weighs it against its own signals and can ignore it

Verifying it worked

The network panel’s Priority column shows the assigned priority, and the check is whether the LCP resource is high from the start rather than upgraded partway. Confirm in the field, not just locally — a change that looks identical on a fast connection can move p75 LCP meaningfully — Real User Monitoring, Largest Contentful Paint.

Where it interacts

  • Resource Hints — the discovery half; use preload when the browser doesn’t know, fetchpriority when it knows but is wrong
  • Largest Contentful Paint — the metric this most directly moves
  • Lazy Loading — the opposite lever, and the one that conflicts if both are applied to one element
  • Image Optimisation — reordering an image request matters much less than the image being a third of the size