dist/codex/shopify-commerce/skills/shopify-performance/SKILL.md
Optimize Shopify performance — Liquid rendering, asset optimization, CDN strategies, Core Web Vitals, Hydrogen caching, image optimization, preloading, and lazy loading. Use when improving Shopify store speed.
npx skillsauth add orcaqubits/agentic-commerce-claude-plugins shopify-performanceInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Fetch live docs:
site:shopify.dev theme performance for theme optimizationsite:shopify.dev hydrogen caching for Hydrogen caching strategiessite:web.dev core web vitals for current CWV guidelines and thresholdssite:shopify.dev image optimization cdn for image URL transformssite:shopify.dev theme speed report for Shopify's built-in speed metrics{% render %} (not {% include %}) — isolated scope prevents variable conflictsO(n²) in Liquid is expensiveforloop iterations with limit: parameter{% assign %} instead of repeating expressions{{ product.title }} not {{ product | json }}all_products[handle] in loops — each is a separate data lookup{{ content_for_header }} scripts (managed by Shopify — cannot remove, but minimize additional scripts)| Anti-Pattern | Why It's Slow | Better Approach |
|-------------|--------------|-----------------|
| Nested for loops | O(n²) rendering | Flatten data, use single loop |
| all_products[handle] in loop | Data fetch per iteration | Pass products via section settings |
| {% include %} with variables | Shared scope causes conflicts | Use {% render %} (isolated) |
| Complex {% if %} chains | Evaluated every render | Simplify conditions, use {% case %} |
| Unused sections in templates | Rendered even if hidden | Remove from JSON template |
{{ 'style.css' | asset_url | stylesheet_tag }} for proper caching<head>media="print" onload="this.media='all'"<script defer> or dynamic import()async attribute)<head>Shopify CDN image optimization:
# Responsive images with srcset
{{ image | image_url: width: 800 }}
{{ image | image_url: width: 400 }}
# Srcset pattern
<img
srcset="{{ image | image_url: width: 400 }} 400w,
{{ image | image_url: width: 800 }} 800w,
{{ image | image_url: width: 1200 }} 1200w"
sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
src="{{ image | image_url: width: 800 }}"
alt="{{ image.alt }}"
loading="lazy"
width="{{ image.width }}"
height="{{ image.height }}"
>
Key image practices:
loading="lazy" for below-the-fold imagesfetchpriority="high" for LCP imagewidth and height to prevent layout shift?width=, ?height=, ?crop=, ?format=Fetch live docs: Web-search
site:shopify.dev image_url filter parametersfor current CDN transform options — new parameters are added over time.
Target: < 2.5 seconds
<link rel="preload" as="image" href="{{ image | image_url: width: 1200 }}">fetchpriority="high" on LCP imageTarget: < 0.1
width and height on all images and mediaaspect-ratio CSS property for responsive media containersTarget: < 200ms
requestIdleCallback or setTimeout(fn, 0)Fetch live docs: CWV thresholds and measurement methodology evolve. Web-search
site:web.dev core web vitals thresholdsfor current targets.
// Pattern: apply cache strategy to storefront query
const data = await storefront.query(QUERY, {
cache: CacheLong(), // products, collections
});
const cart = await storefront.query(CART_QUERY, {
cache: CacheShort(), // dynamic data
});
| Strategy | Use For |
|----------|---------|
| CacheLong() | Products, collections, pages |
| CacheShort() | Cart, personalized content |
| CacheNone() | Customer-specific data |
| CacheCustom({...}) | Fine-tuned scenarios |
Fetch live docs for exact TTL values — Hydrogen caching defaults may change across versions.
defer() in loaders for non-critical data<Suspense> + <Await><Link prefetch="intent">Shopify's global CDN:
| Tool | What It Measures | |------|-----------------| | Shopify Theme Speed Report | Overall theme score in admin | | Google Lighthouse | CWV + performance audit | | WebPageTest | Real-world loading waterfall | | Chrome DevTools Performance | JS profiling, layout shifts | | Search Console CWV Report | Field data from real users |
font-display: swap for custom fontsFetch the Shopify performance documentation, Core Web Vitals guides, and Hydrogen caching docs for exact optimization techniques and current best practices before implementing.
development
Build with Spree's headless Next.js storefront — the official `spree/storefront` repo (Next.js 16 App Router with Server Actions and Turbopack, React 19 Server Components, Tailwind CSS 4, TypeScript 5, `@spree/sdk`, Sentry), server-only auth (httpOnly JWT cookies + publishable key), MeiliSearch faceted catalog, one-page checkout with Apple/Google Pay/Klarna/Affirm/SEPA, multi-region market routing, GA4 + JSON-LD SEO, and Vercel/Docker deployment. Use when forking or customizing the storefront, or evaluating headless adoption.
tools
Build Spree extensions as Rails engines — gem scaffolding, `bin/rails g spree:extension`, mounting routes/migrations/assets, the modern `prepend` decorator pattern (`*_decorator.rb` with `self.prepended(base)`), generators (`spree:model_decorator`, `spree:controller_decorator`), the four customization surfaces in preference order (Events > Webhooks > Dependencies > Decorators), Spree::Dependencies for swapping service objects, gem release/versioning, and the deprecated Deface engine. Use when building a reusable Spree extension or adding non-trivial customization to an app.
development
Build with Spree's event bus and Webhooks 2.0 — `Spree::Events` publication, `Spree::Subscriber` DSL with `subscribes_to` and `on`, wildcard matching, lifecycle events (`{model}.created/.updated/.deleted` via `publishes_lifecycle_events`), the canonical event catalog (order.*, payment.*, shipment.*, product.*), Webhooks 2.0 endpoints, HMAC-SHA256 signing (`X-Spree-Webhook-Signature`), exponential-backoff retries, and Sidekiq job orchestration. Use when wiring event-driven business logic, building webhook consumers, or replacing ActiveSupport callback chains.
tools
Cross-cutting Spree development patterns — the customization preference hierarchy (Events > Webhooks > Dependencies > Decorators), `Spree::Dependencies` service-object swapping, the `_decorator.rb` + `prepend` + `self.prepended` idiom, idempotent subscribers and webhook receivers, multi-store scoping discipline, prefixed IDs, calculator polymorphism (shipping/promotion/tax share the base), service-object composition with `dry-monads` or simple results, why to avoid `class_eval` reopening and Deface, and Spree-on-Rails idioms (Hotwire/Turbo Stimulus, ActiveStorage, Action Cable, Sidekiq). Use when designing the architecture of a Spree extension or solving cross-cutting concerns.