5 Quick Wins to Speed Up Your Shopify Theme
Drop LCP and boost conversion with these low-risk tweaks: image policy, app audit, render budget, fonts, and Liquid includes.
1) Set an Image Policy
Most Shopify LCP issues are images. Make the rules explicit and enforce them in theme code:
Policy: Next-gen formats (`avif, webp`), fixed dimensions, `loading="lazy"` below the fold, and responsive sizes via `srcset`/`sizes` or
image_url
filters.
Liquid snippet (hero image)
{% raw %}{% assign hero = section.settings.hero | default: product.featured_image %}
{% if hero %}
<img
src="{{ hero | image_url: width: 1200, format: 'webp' }}"
srcset="
{{ hero | image_url: width: 640, format: 'webp' }} 640w,
{{ hero | image_url: width: 960, format: 'webp' }} 960w,
{{ hero | image_url: width: 1200, format: 'webp' }} 1200w,
{{ hero | image_url: width: 1600, format: 'webp' }} 1600w"
sizes="(max-width: 768px) 95vw, 1200px"
width="1200" height="{{ 1200 | divided_by: hero.aspect_ratio | round }}"
alt="{{ hero.alt | escape }}"
decoding="async"
fetchpriority="high"
>
{% endif %}{% endraw %}
Tip: Use fetchpriority="high"
only for the single LCP image on the start view.
2) Run an App Audit
Each app can inject CSS/JS and 3rd-party requests. Keep what drives revenue; remove, delay, or conditionally load the rest.
- Inventory: In Admin → Apps, list all apps & their theme assets/snippets.
- Measure: Lighthouse + Network tab → find scripts > 50KB or long tasks > 50 ms.
- Action: Disable pages where an app isn’t needed using template checks or route guards.
Conditional load example
{% raw %}{% if template.name == 'product' %}
{% render 'reviews-widget' %}
{% endif %}{% endraw %}
3) Create a Render Budget
Set guardrails so your theme stays fast as features ship.
- LCP: < 2.5s on 4G/Slow-3G test profile
- Total JS: < 150KB compressed on first load
- Requests: < 60 on homepage (first view)
Budget gate in CI (pseudo)
# run in CI after build
lighthouse-ci https://preview-url \
--budgetsFile=budgets.json --assert.assertions="categories.performance<=0.9:warn"
budgets.json
sample
[
{ "path": "/*", "resourceCounts": [{ "resourceType": "script", "budget": 20 }], "timings": [{ "metric": "interactive", "budget": 4000 }] }
]
4) Fix Your Fonts
Fonts are sneaky LCP killers. Serve fewer, smaller, and earlier.
- Use system stack or a single custom family (wght subset only).
- Self-host WOFF2, add
preload
+font-display: swap
. - Inline a tiny critical CSS block for above-the-fold text.
Theme head include
<link rel="preload" as="font" type="font/woff2" href="{{ 'Inter-400.woff2' | asset_url }}" crossorigin>
<style>@font-face{font-family:Inter;src:url({{ 'Inter-400.woff2' | asset_url }}) format('woff2');font-weight:400;font-style:normal;font-display:swap}</style>
5) Slim Your Liquid Includes
Big partials render slowly. Break them up and avoid heavy logic on first paint.
Replace global monoliths (e.g., a
header
that renders mega menus, search, recommendations) with lazy sections or defer non-critical includes below the fold.
Defer non-critical snippet
{% raw %}{% capture after_fold %}
{% render 'size-guide' %}
{% render 'recently-viewed' %}
{% endcapture %}
<div id="after-fold" hidden>{{ after_fold }}</div>
<script>requestIdleCallback(()=>{document.getElementById('after-fold').hidden=false})</script>{% endraw %}
One-Page Checklist
- Hero/LCP image uses
image_url
widths,sizes
, and correct dimensions. - Apps audited; non-essentials removed or loaded only where needed.
- Budgets defined (LCP, total JS, requests) and enforced in CI.
- Fonts: one family, WOFF2, preload +
font-display: swap
. - Liquid includes trimmed; non-critical widgets deferred.