Blog Performance 6 min read

How decoding=async Improves Placeholder Image Rendering

decoding=async lets the browser decode placeholder images off the main thread, reducing jank and keeping scrolling smooth during heavy page loads.

img decoding asyncplaceholder imagesbrowser renderingimage performancemain thread
How decoding=async Improves Placeholder Image Rendering

Image decoding is CPU work. Without guidance, the browser synchronously decodes images on the main thread before painting, which can delay rendering and cause jank during scroll on image-heavy pages.

The decoding=async attribute tells the browser it can defer image decoding off the main thread. For placeholder images used in grids, feeds, and galleries, this single attribute often eliminates the micro-stutter that appears when dozens of images load in quick succession.

The rendering bottleneck

Image decoding blocks the main thread by default

After a browser fetches image bytes, it must decode the compressed data into raw pixels before the image can be painted. JPEG decoding means running a DCT, PNG decoding means inflating zlib data, and even SVGs require parsing and rasterizing. This work happens on the main thread by default.

On a page with 20 product cards, the browser may decode all 20 images synchronously as they load. Each decode call occupies the main thread, blocking scroll handlers, animations, and user input responses. On a mid-range Android device this manifests as visible stutter when a grid of placeholders appears.

The browser does not know ahead of time whether an image is important or decorative. It defaults to synchronous decoding for predictable behavior. decoding=async opts out of that default for images where a few milliseconds of decoding delay is acceptable.

Attribute syntax

Using decoding=async on placeholder img elements

The decoding attribute accepts three values: sync, async, and auto. Sync forces synchronous main-thread decoding. Async explicitly moves decoding off the main thread. Auto, the default, lets the browser choose based on its own heuristics.

For placeholder images in lists, grids, and feeds — any surface where many images load near-simultaneously — async is the right choice. The image may appear a frame or two later than sync would produce, but the main thread stays free for scroll and interaction events.

Implementation text
<!-- Placeholder image with async decoding -->
<img
  src="https://fallback.pics/api/v1/400x300/E4E4E7/71717A?text=Product"
  width="400"
  height="300"
  loading="lazy"
  decoding="async"
  alt="Product preview"
/>

<!-- Avatar grid item: async decoding and lazy loading -->
<img
  src="https://fallback.pics/api/v1/avatar/80?text=AB"
  width="80"
  height="80"
  loading="lazy"
  decoding="async"
  alt="User avatar"
/>

When to use sync

Hero images where a decoding delay changes LCP

For the primary hero image or any image that is the Largest Contentful Paint element, decoding=sync ensures the image is decoded and painted as part of the earliest possible frame. With async, the browser may defer decoding until after the first paint, increasing measured LCP.

The tradeoff is clear: use async for below-the-fold images and multi-image grids, and use sync (or leave the default) for the single hero image that is the LCP candidate. Mixing both attributes on a page based on image position is normal and intentional.

Placeholder-specific benefit

Grids of fallback placeholders benefit most from async decoding

Placeholder images are often simpler to decode than real photos — an SVG or a solid-color PNG is much cheaper than a complex JPEG. Even so, when a product grid renders 30 placeholders simultaneously, the cumulative decode work adds up.

With decoding=async on each grid item, the browser schedules those decode jobs on image decode workers rather than on the main thread. Scroll performance during the placeholder phase stays smooth, and when real images swap in, the same attribute continues to help.

Test this on a CPU-throttled device. Open DevTools Performance panel, enable 4x CPU slowdown, and load a product grid with and without decoding=async. The flame chart will show the difference in main-thread image decode blocks.

Combining attributes

decoding, loading, and fetchpriority work at different stages

These three attributes control different phases of image delivery. loading controls when the fetch begins. fetchpriority controls how urgently the browser fetches the resource. decoding controls when and on which thread the browser processes the fetched bytes.

A complete below-fold placeholder gets: loading=lazy (defer fetch), fetchpriority=low (low urgency), decoding=async (off-thread decode). A hero placeholder gets: loading=eager (fetch now), fetchpriority=high (maximum urgency), decoding=sync (decode in-frame for LCP).

Implementation text
<!-- Complete attribute set for a below-fold placeholder -->
<img
  src="https://fallback.pics/api/v1/600x400/F4F4F5/A1A1AA?text=Loading"
  width="600"
  height="400"
  loading="lazy"
  fetchpriority="low"
  decoding="async"
  alt="Loading preview"
/>

Framework defaults

Next.js, Astro, and Nuxt handle decoding differently

Next.js Image component sets decoding=async by default for all images. This is a reasonable default for most product grids. If you bypass the Image component and use a raw img tag, you opt out of that default.

Astro's Image component also sets decoding=async. Nuxt Image and @nuxt/image follow similar defaults. When you use a placeholder URL directly in a raw img tag — for example in an onerror fallback — you need to add the attribute yourself.

Implementation text
# Documentation and API reference
https://fallback.pics/docs/
https://fallback.pics/placeholder-image-api/

# Related posts
https://fallback.pics/blog/fetchpriority-critical-image-fallbacks/
https://fallback.pics/blog/image-loading-best-practices-for-better-ux/

Key takeaways

What to standardize before shipping

  • decoding=async moves image decode work off the main thread, reducing scroll jank in image-heavy grids.
  • Use sync or the default (auto) for the primary hero image that is the LCP candidate.
  • Placeholder grids with 10+ items benefit the most from async decoding on mid-range devices.
  • decoding, loading, and fetchpriority each control a different phase of image delivery — all three matter.
  • Add decoding=async manually when using raw img fallback tags; framework Image components often set it automatically.

Production fallback layer

Use fallback.pics anywhere an image URL is accepted.

Start with one deterministic URL and standardize fallback behavior across your design system.

Read the docs