Shopify Image Optimization Guide
Stop slowing down your storefronts. Learn the modern, optimal ways to render responsive images using Liquid.
Share with Shopify developers — useful guides spread faster in theme dev communities.
Why image Liquid matters
Heavy or wrongly loaded images dominate mobile performance audits. Shopify's CDN handles resizing and modern formats when you use image_url and image_tag—not hardcoded asset URLs or the deprecated img_url filter.
image_url: sized CDN URLs
{% if section.settings.image != blank %}
{{ section.settings.image | image_url: width: 800 }}
{% endif %}
During theme customization, this issue often appears when image_picker settings are blank—always guard before calling filters.
image_tag: srcset, width, height, loading
{{ section.settings.image
| image_url: width: 1200
| image_tag:
loading: 'lazy',
width: section.settings.image.width,
height: section.settings.image.height,
sizes: '(min-width: 990px) 50vw, 100vw',
alt: section.settings.image.alt | escape
}}
Explicit width and height on the tag reserve space and reduce cumulative layout shift (CLS). Pair with a sizes attribute so the browser picks an appropriate file from the generated srcset.
Loading strategy
- Hero / LCP image:
loading: 'eager'—not lazy - Product grids and below-fold bands:
loading: 'lazy' - Cap widths in sliders—do not request 4000px for thumbnails
Common mistakes
- Leaving
img_urlin legacy snippets - CSS background-image instead of theme-native
image_tag - Missing
sizes—browser downloads oversized files - Empty alt attributes on decorative vs informative images
Takeaway
Replace deprecated filters, guard blanks, size intentionally, and split eager vs lazy by viewport position. Broader launch checks: Theme Performance Tips.
LCP and hero images on production stores
The largest contentful paint image is almost always the homepage or collection hero. Use image_tag with explicit width, loading: 'eager', and fetchpriority: 'high' where supported—not lazy loading on the hero. Below-the-fold product grids use loading: 'lazy'.
Section settings vs product images
{% if section.settings.image != blank %}
{{ section.settings.image
| image_url: width: 1600
| image_tag:
loading: 'lazy',
sizes: '(min-width: 990px) 50vw, 100vw',
alt: section.settings.image.alt | escape
}}
{% endif %}
Always guard blank image_picker values—merchants save sections before uploading assets.
Mistakes we still audit on rescue themes
- Deprecated
img_urlfilter still in snippets - Full-resolution PNG heroes on mobile PDP filmstrips
- Missing
sizeson responsive images—browser downloads oversized files - Background images in CSS instead of theme-native
image_tagpatterns
Performance checklist
- Replace all
img_urlwithimage_url - Cap block image widths in sliders
- Lazy-load below-fold grids
- Test Lighthouse mobile on staging with apps enabled
Broader launch gates: performance checklist before launch and theme performance tips.
Topic cluster
Theme Development
Dawn, performance, images, and production theme workflows.
Convert HTML to Shopify Liquid
Paste HTML & generate Liquid with schema, blocks, and scoped CSS. No signup required.
Share
Share this guide
Found this guide useful? Share it with other Shopify developers on LinkedIn, X, or Reddit.