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.
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.
<!-- 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).
<!-- 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.
# 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.