Fetch Priority API: Taking Control of Resource Loading Order

When a browser discovers resources while parsing a page, it assigns each a fetch priority to determine download order. Chrome's default logic considers resource type, document position, and attributes like async or defer. The Fetch Priority API, exposed via the fetchpriority HTML attribute (with values high or low), gives developers a way to hint at relative importance and override default behavior when the standard heuristics aren't ideal.

This signal works alongside—not instead of—existing optimization techniques. Preload is still the right tool for telling the browser about resources it won't discover early, like CSS background images or fonts referenced in stylesheets. Preconnect remains useful for warming up cross-origin connections. Fetch Priority complements these by letting you fine-tune the download sequence for resources the browser already knows about.

While Chrome assigns a High priority to fetches made via the fetch() API, the Fetch API also accepts a priority property for programmatic control over data requests.

When Default Priorities Fall Short

You already have several levers that indirectly influence relative priority: controlling tag order, preloading critical assets, using async and defer for scripts, and lazy-loading below-the-fold content. But certain scenarios expose gaps in the browser's default logic where Fetch Priority can provide meaningful gains:

  • Multiple above-the-fold images don't all need the same priority. An image carousel, for instance, benefits from marking the initial visible slide high and the remainder low.
  • Hero images are discovered at Low priority and only boosted after layout confirms they're in the viewport—a delay that hurts LCP. An explicit fetchpriority="high" lets the image start loading at a high priority immediately. Chrome's automatic Medium assignment to the first five larger images mitigates this, but doesn't eliminate the need for an explicit hint on the LCP image.
  • async and defer scripts are downloaded at Low priority despite often being user-critical. Fetch Priority can elevate them back toward High while preserving non-blocking behavior.
  • Background fetch() API calls compete at High priority with interactive API calls. Lowering the priority of the background work lets the interactive requests win.
  • CSS and fonts default to High, but important subresources within those groups exist. Applying low to the ones that are not critical can better sequence their use of bandwidth.

Chrome's Priority Model

Chrome computes resource priority from a combination of resource type, reference order, and script attributes. Resources sharing the same computed priority are fetched in document discovery order. You can inspect these assignments in DevTools under the Network tab; enable the priority column via right-clicking the column header. When a resource's priority shifts during loading, the Big request rows view displays both the initial and final states.

A common optimization target is the LCP image. Even when preloaded, such an image may receive a low priority and be delayed behind other early-arriving resources. Combining <link rel="preload"> with fetchpriority="high" is the recommended pattern for LCP candidates that the parser wouldn't discover early, like CSS backgrounds. For markup images, fetchpriority="high" reduces the time-to-first-byte for that resource and improves LCP without requiring preload.

Using the fetchpriority attribute

For resources loaded through <link>, <img>, or <script> tags, the fetchpriority attribute lets you signal a suggested download priority to the browser. The attribute accepts three values:

  • high: Tells the browser you want to prioritize this resource above its usual handling (but the browser's own heuristics can still override this).
  • low: Tells the browser to deprioritize this resource (its heuristics permitting).
  • auto: The default, which leaves priority decisions entirely to the browser.

The attribute works alongside the script-equivalent priority property in the Fetch API:

<!-- We don't want a high priority for this above-the-fold image -->
<img src="https://web.dev/images/in_viewport_but_not_important.svg" fetchpriority="low" alt="I'm an unimportant image!">

<!-- We want to initiate an early fetch for a resource, but also deprioritize it -->
<link rel="preload" href="https://web.dev/js/script.js" as="script" fetchpriority="low">

<script>
  fetch('https://example.com/', {priority: 'low'})
  .then(data => {
    // Trigger a low priority fetch
  });
</script>

How browser heuristics and fetchpriority combine

The computed priority for any given resource depends on its type and the value of fetchpriority. The table below shows how different resources respond to each setting; the ◉ symbol marks the default (auto) priority for each resource type:

  Load in layout-blocking phase Load one at a time in layout-blocking phase
Blink
Priority
VeryHigh High Medium Low VeryLow
DevTools
Priority
Highest High Medium Low Lowest
Main Resource
CSS (early**) ⬆◉
CSS (late**)
CSS (media mismatch***) ⬆*** ◉⬇
Script (early** or not from preload scanner) ⬆◉
Script (late**)
Script (async/defer) ◉⬇
Font
Font (rel=preload) ⬆◉
Import
Image (in viewport - after layout) ⬆◉
Image (first 5 images > 10,000px2)
Image ◉⬇
Media (video/audio)
XHR (sync) - deprecated
XHR/fetch* (async) ⬆◉
Prefetch
XSL

Importantly, fetchpriority only adjusts priority relative to the browser's existing baseline for that resource type. It does not directly force a resource to a specific High or Low category. For instance, setting fetchpriority="high" on render-blocking CSS keeps it at the top of the "Very High"/"Highest" tier, while fetchpriority="low" still leaves it at "High" — not exactly the literal value you passed in, but a deliberate shift from the default.

Common application patterns

Boost the LCP image

Applying fetchpriority="high" to your Largest Contentful Paint (LCP) image is a direct way to get it in flight sooner:

<img src="lcp-image.jpg" fetchpriority="high">

Testing on the Google Flights page with an LCP background image illustrates the impact: when the resource was given high priority, LCP time improved from 2.6s to 1.9s.

An experiment conducted using Cloudflare workers to rewrite the Google Flights page using Fetch Priority.

Deprioritize visible but non-essential images

Images within the viewport but outside the core user task (such as non-visible slides in a carousel) can get an unhelpful priority bump from the browser's heuristics. Adding fetchpriority="low" corrects this:

<ul class="carousel">
  <img src="img/carousel-1.jpg" fetchpriority="high">
  <img src="img/carousel-2.jpg" fetchpriority="low">
  <img src="img/carousel-3.jpg" fetchpriority="low">
  <img src="img/carousel-4.jpg" fetchpriority="low">
</ul>

Even when those carousel images aren't visible, the browser can raise them to high simply for being "close enough" to the viewport — which would also block a loading="lazy" attribute from working as intended. An explicit low priority is the more reliable control.

Testing in the Oodle demo app used this technique on non-load-critical images, yielding a 2-second reduction in page load time.

A side-by-side comparison of Fetch Priority when used on the Oodle app's image carousel. On the left, the browser sets default priorities for carousel images, but downloads and paints those images around two seconds slower than the example on the right, which sets a higher priority on only the first carousel image.
Using high priority for only the first carousel image lets the page load faster.

Reduce the impact of preloads

Preloaded resources that aren't immediately needed for rendering compete with critical assets for bandwidth. Dropping their priority is straightforward:

<!-- Lower priority only for non-critical preloaded scripts -->
<link rel="preload" as="script" href="critical-script.js">
<link rel="preload" as="script" href="non-critical-script.js" fetchpriority="low">

<!-- Preload CSS without blocking render, or other resources -->
<link rel="preload" as="style" href="theme.css" fetchpriority="low" onload="this.rel='stylesheet'">

Right-size scripts

Scripts required for interactivity can load quickly without blocking first paint when marked async and given higher priority:

<script src="async_but_important.js" async fetchpriority="high"></script>

Conversely, a script that doesn't need to execute immediately (but must run in document order without async) can be marked with low priority to avoid starving earlier content:

<script src="blocking_but_unimportant.js" fetchpriority="low"></script>

Scripts that require the full DOM are better served by the defer attribute, which executes after DOMContentLoaded — or by an async tag at the page's end.

Manage competing fetch() calls

The browser assigns high default priority to all fetch requests. When several are fired at once, mark the critical ones explicitly and dial down the rest:

// Important validation data (high by default)
let authenticate = await fetch('/user');

// Less important content data (suggested low)
let suggestedContent = await fetch('/content/suggested', {priority: 'low'});

Implementation caveats

Fetch Priority behaves as a hint rather than a command, and several environment factors can dilute its effect:

  • It is not a preload substitute. Preload issues a mandatory fetch to aid early discovery; Fetch Priority only changes the priority of a fetch already scheduled. The two can also conflict. A high hint on an LCP image adds little if that image is the first preloaded element in <head>, but can help meaningfully when a preload appears later in the resource order. For a critical CSS background image, preloading it with fetchpriority="high" is recommended.
  • Network conditions matter. Priority adjustments have a larger measurable impact where resources contend for bandwidth — particularly over HTTP/1.x (no parallel downloads) or low-bandwidth HTTP/2/3 links.
  • CDN support can undermine the hint. CDNs apply HTTP/2 and HTTP/3 prioritization inconsistently, which can mask Fetch Priority's protocol-level effects. However, the browser also uses these priorities internally — delaying low-priority asks (such as images) to focus on critical <head> work — so setting them correctly is worthwhile even if upstream support is variable.
  • Adjust over time. Fetch Priority might not fit cleanly into an initial architecture, but after the page is live you can inspect assigned priorities against expectations and apply the hint as a targeted optimization.

Practical preload placement

Because preload behavior and its interaction with Fetch Priority can be subtle, order matters:

  • Entering a preload via HTTP header places it first in load order.
  • For anything with Medium priority or above, in-document preloads typically load in parser order — a preload early in the HTML body runs well before one placed later.
  • Place font preloads near the end of <head> or at the start of <body>.
  • Set import preloads (import() or modulepreload) only after the script tag that needs them, prioritizing the script parse and execution while dependencies download.
  • Image preloads default to Low/Medium priority; sequence them relative to async scripts and other low-priority elements.

A brief history

Chrome first trialed this concept as an origin trial in 2018, and again in 2021 using an importance attribute, when the API was known as Priority Hints. Through the standards process it evolved to the current form: fetchpriority for HTML and the priority option for the JavaScript Fetch API, with the unified name Fetch Priority.

Bottom line

For developers tuning Core Web Vitals and LCP, Fetch Priority adds precise control over the order in which resources load — complementing, rather than replacing, mechanisms like preload.