Developer reference

Shopify Liquid Cheat Sheet

Interactive quick reference for tags, filters, objects, and schema. Search or browse by category.

Most used

Most Used

Render Section Setting

Outputs a text or basic setting value from the section schema.

When to use:Use this whenever you want to display data that a merchant has entered in the Theme Editor for the current section.
Make sure to escape plain text using {{ section.settings.title | escape }} to prevent malicious code injection.
{{ section.settings.title }}
Most Used

Render Image (Modern)

The modern, performant way to render an image picker setting with automatic WebP support.

When to use:When outputting an image selected by the merchant. Never use the deprecated img_url filter.
Read our Image Optimization Guide for more speed tips.
{{ section.settings.image | image_url: width: 800 | image_tag: loading: 'lazy', class: 'my-custom-class' }}
Most Used

Basic For Loop

Loops through section blocks to render repeated content like a gallery or FAQ.

When to use:Use this to create scalable sections where merchants can add/remove items freely.
Always include block.shopify_attributes inside the loop so the Theme Editor can hook into the block for live editing.
{% for block in section.blocks %}
  <div {{ block.shopify_attributes }}>
    {{ block.settings.heading }}
  </div>
{% endfor %}

All snippets

Most Used

Render Section Setting

Outputs a text or basic setting value from the section schema.

When to use:Use this whenever you want to display data that a merchant has entered in the Theme Editor for the current section.
Make sure to escape plain text using {{ section.settings.title | escape }} to prevent malicious code injection.
{{ section.settings.title }}
Most Used

Render Image (Modern)

The modern, performant way to render an image picker setting with automatic WebP support.

When to use:When outputting an image selected by the merchant. Never use the deprecated img_url filter.
Read our Image Optimization Guide for more speed tips.
{{ section.settings.image | image_url: width: 800 | image_tag: loading: 'lazy', class: 'my-custom-class' }}
Most Used

Basic For Loop

Loops through section blocks to render repeated content like a gallery or FAQ.

When to use:Use this to create scalable sections where merchants can add/remove items freely.
Always include block.shopify_attributes inside the loop so the Theme Editor can hook into the block for live editing.
{% for block in section.blocks %}
  <div {{ block.shopify_attributes }}>
    {{ block.settings.heading }}
  </div>
{% endfor %}
Product

Product Title

Outputs the title of the current product.

When to use:On product templates, or inside a loop over collection.products.
{{ product.title }}
Product

Product Price Formatting

Formats the product price according to the store's currency settings.

When to use:Whenever you display a price. Use money_without_trailing_zeros if you want cleaner rounded numbers.
{{ product.price | money }}
<!-- Compare at price -->
{{ product.compare_at_price | money }}
Product

Product Vendor & Type

Outputs the vendor (brand) and product type.

When to use:Useful for displaying brand names above the title or filtering.
{{ product.vendor }}
{{ product.type }}
Product

Product Tags Loop

Iterates through all tags attached to a product.

When to use:Great for rendering 'New' or 'Sale' badges dynamically.
{% for tag in product.tags %}
  <span class="badge">{{ tag }}</span>
{% endfor %}
Product

First Available Variant

Gets the first variant that is currently in stock.

When to use:Use this to determine the default price to show on page load before a user selects a size/color.
{% assign current_variant = product.selected_or_first_available_variant %}
{{ current_variant.price | money }}
Product

Product Media Gallery

Loops through all images, videos, and 3D models attached to a product.

When to use:When building custom product page image galleries or sliders.
{% for media in product.media %}
  {% render 'media', media: media %}
{% endfor %}
Product

Product Description

Outputs the main product description HTML from the admin.

When to use:On product pages below the title and price. Wrap in a .rte class for consistent typography.
Use strip_html only if you need plain text previews—not on the full product page.
<div class="product-description rte">
  {{ product.description }}
</div>
Product

Product Description (Plain Preview)

Strips HTML tags for short previews in cards or search results.

When to use:Product cards, collection grids, or quick-view snippets where full HTML is too heavy.
{{ product.description | strip_html | truncate: 120 }}
Product

Product URL

The canonical URL path for the current product.

When to use:Linking to product pages from featured sections, blogs, or custom landing pages.
<a href="{{ product.url }}">{{ product.title }}</a>
Product

Check Product Availability

Returns true if at least one variant can be purchased.

When to use:Before showing add-to-cart buttons or urgency messaging.
{% if product.available %}
  <button type="submit" name="add">Add to cart</button>
{% else %}
  <button disabled>Sold out</button>
{% endif %}
Product

Featured Product Image

Renders the product's main image using modern Shopify image filters.

When to use:Product cards and hero images. Use loading: 'eager' only for above-the-fold images.
Read related guide →
{% if product.featured_image %}
  {{ product.featured_image | image_url: width: 1200 | image_tag: loading: 'eager', alt: product.featured_image.alt | escape }}
{% endif %}
Product

Featured Media (OS 2.0)

Accesses the primary media object, which may be an image, video, or 3D model.

When to use:Modern themes that support video and 3D on the product page.
{% if product.featured_media %}
  {% render 'product-media', media: product.featured_media %}
{% endif %}
Product

Loop All Variants

Iterates every variant (size, color, etc.) on a product.

When to use:Building custom variant pickers or JSON data for JavaScript.
{% for variant in product.variants %}
  <option value="{{ variant.id }}" {% unless variant.available %}disabled{% endunless %}>
    {{ variant.title }} — {{ variant.price | money }}
  </option>
{% endfor %}
Product

Variant SKU & Barcode

Outputs inventory identifiers for the selected or first available variant.

When to use:B2B catalogs, wholesale pages, or fulfillment detail modals.
{% assign v = product.selected_or_first_available_variant %}
<p>SKU: {{ v.sku }}</p>
<p>Barcode: {{ v.barcode }}</p>
Product

Product Options (Size, Color)

Loops option names and values—for example Color: Red, Blue.

When to use:Custom variant UI when you are not using Shopify's default product form.
{% for option in product.options_with_values %}
  <fieldset>
    <legend>{{ option.name }}</legend>
    {% for value in option.values %}
      <label><input type="radio" name="{{ option.name }}" value="{{ value }}"> {{ value }}</label>
    {% endfor %}
  </fieldset>
{% endfor %}
Product

Check for Specific Tag

Shows content only when a product has a given tag.

When to use:Sale badges, new-arrival labels, or hiding features for certain product types.
{% if product.tags contains 'sale' %}
  <span class="badge badge--sale">On sale</span>
{% endif %}
Collection

Collection Title & Description

Outputs the collection's title and its rich text description.

When to use:On the collection template hero banner.
<h1>{{ collection.title }}</h1>
<div>{{ collection.description }}</div>
Collection

Loop Collection Products

Iterates through products in a specific collection.

When to use:When building product grids. The 'else' block renders if the collection is empty.
{% for product in collection.products %}
  <h2>{{ product.title }}</h2>
{% else %}
  <p>No products found.</p>
{% endfor %}
Collection

Paginate Collection

Required for collections with more than 50 products.

When to use:Always use pagination on collection pages. Shopify limits standard loops to 50 items.
Read related guide →
{% paginate collection.products by 12 %}
  {% for product in collection.products %}
    <!-- Render product card -->
  {% endfor %}
  {{ paginate | default_pagination }}
{% endpaginate %}
Collection

Collection URL & Handle

Builds links and CSS hooks from the collection object.

When to use:Breadcrumbs, collection cards, and filtering UI.
<a href="{{ collection.url }}">{{ collection.title }}</a>
<!-- Handle for data attributes -->
data-collection="{{ collection.handle }}"
Collection

Collection Product Count

Shows how many products belong to the collection.

When to use:Collection headers, filters sidebar, or SEO-friendly collection intros.
<p>{{ collection.products_count }} products</p>
Collection

Collection Featured Image

Renders the image uploaded for the collection in the admin.

When to use:Collection banner heroes and navigation tiles.
{% if collection.image %}
  {{ collection.image | image_url: width: 1600 | image_tag: loading: 'lazy', alt: collection.title | escape }}
{% endif %}
Collection

Collection from Section Setting

Loops products from a collection the merchant picked in the theme editor.

When to use:Homepage featured collection rows driven by a collection picker setting.
{% assign featured = section.settings.collection %}
{% if featured != blank %}
  {% for product in featured.products limit: section.settings.limit %}
    {% render 'product-card', product: product %}
  {% endfor %}
{% endif %}
Blog & Article

Paginate Blog Articles

Pagination works for blogs too—not only collections.

When to use:Blog listing templates with more than a handful of posts.
{% paginate blog.articles by 6 %}
  {% for article in blog.articles %}
    <h2><a href="{{ article.url }}">{{ article.title }}</a></h2>
  {% endfor %}
  {{ paginate | default_pagination }}
{% endpaginate %}
Cart

Cart Item Count & Total

Displays the total number of items and the total price of the cart.

When to use:In the header cart icon or cart drawer header.
{{ cart.item_count }} items
{{ cart.total_price | money_with_currency }}
Cart

Cart Items Loop

Loops through all items currently in the cart.

When to use:When building custom cart pages or ajax cart drawers.
{% for item in cart.items %}
  <img src="{{ item.image | image_url: width: 100 }}">
  <h3>{{ item.product.title }}</h3>
  <p>Qty: {{ item.quantity }}</p>
  <p>{{ item.final_line_price | money }}</p>
{% endfor %}
Cart

Empty Cart Check

Shows different markup when the cart has zero items.

When to use:Cart drawer, cart page, and mini-cart components.
{% if cart.item_count == 0 %}
  <p>Your cart is empty.</p>
  <a href="{{ routes.all_products_collection_url }}">Continue shopping</a>
{% else %}
  <!-- cart items -->
{% endif %}
Cart

Cart Subtotal vs Total

Displays line totals; cart.total_price includes discounts where applicable.

When to use:Cart summary sidebars. Pair with shipping/tax messaging at checkout.
<p>Subtotal: {{ cart.total_price | money }}</p>
<p>Items: {{ cart.item_count }}</p>
Cart

Line Item Variant Title

Shows the variant name (e.g. Size M / Color Black) for each cart line.

When to use:Cart drawers and order review lists so customers confirm the right variant.
{% for item in cart.items %}
  <p class="line-item__variant">{{ item.variant.title }}</p>
{% endfor %}
Cart

Line Item Properties

Outputs custom properties added at add-to-cart (engraving, gift message, etc.).

When to use:Personalized products, upload fields, or B2B purchase order numbers.
{% for item in cart.items %}
  {% unless item.properties == empty %}
    <ul>
      {% for property in item.properties %}
        <li>{{ property.first }}: {{ property.last }}</li>
      {% endfor %}
    </ul>
  {% endunless %}
{% endfor %}
Cart

Cart Note Field

Outputs the optional note customers leave for the store.

When to use:Cart page or drawer when you want delivery or gift instructions.
<textarea name="note">{{ cart.note }}</textarea>
Customer

Check if Logged In

Checks if a customer is currently logged into their account.

When to use:For dynamic header links or gating wholesale content.
{% if customer %}
  Welcome back, {{ customer.first_name }}!
  <a href="{{ routes.account_url }}">My Account</a>
{% else %}
  <a href="{{ routes.account_login_url }}">Log In</a>
{% endif %}
Customer

Customer Full Name

Outputs first and last name, or a combined name when available.

When to use:Account dashboards, welcome messages, and order history headers.
{{ customer.name }}
<!-- Or separately -->
{{ customer.first_name }} {{ customer.last_name }}
Customer

Customer Account Links

Uses Shopify route objects for correct login, register, and logout URLs.

When to use:Header navigation and mobile menus—never hardcode /account/login paths.
<a href="{{ routes.account_url }}">Account</a>
<a href="{{ routes.account_login_url }}">Log in</a>
<a href="{{ routes.account_register_url }}">Create account</a>
<a href="{{ routes.account_logout_url }}">Log out</a>
Customer

Customer Email & Orders

Shows account email and loops recent orders on the account page.

When to use:Account landing pages and loyalty program sections.
<p>{{ customer.email }}</p>
{% for order in customer.orders limit: 5 %}
  <a href="{{ order.customer_url }}">Order {{ order.name }} — {{ order.total_price | money }}</a>
{% endfor %}
Customer

Default Customer Address

Outputs the customer's default shipping address when set.

When to use:Checkout shortcuts or account profile summaries.
{% if customer.default_address %}
  <address>
    {{ customer.default_address.address1 }}<br>
    {{ customer.default_address.city }}, {{ customer.default_address.province_code }} {{ customer.default_address.zip }}
  </address>
{% endif %}
Blog & Article

Blog Articles Loop

Loops through articles in a specific blog (e.g., 'news').

When to use:To display recent news on the homepage.
{% for article in blogs['news'].articles limit: 3 %}
  <h2>{{ article.title }}</h2>
  <p>{{ article.excerpt_or_content | truncatewords: 20 }}</p>
  <a href="{{ article.url }}">Read more</a>
{% endfor %}
Blog & Article

Article Title & URL

Standard article heading and permalink on article templates.

When to use:article.liquid template header area.
<h1>{{ article.title }}</h1>
<p><time datetime="{{ article.published_at | date: '%Y-%m-%d' }}">{{ article.published_at | date: format: 'abbreviated_date' }}</time></p>
Blog & Article

Article Content

Outputs the full article body HTML from the blog editor.

When to use:Main column on article pages. Use .rte for typography styles.
<div class="article-content rte">
  {{ article.content }}
</div>
Blog & Article

Article Author & Image

Shows byline and featured image when present.

When to use:Editorial layouts and magazine-style blog templates.
{% if article.image %}
  {{ article.image | image_url: width: 1200 | image_tag: loading: 'lazy', alt: article.title | escape }}
{% endif %}
<p>By {{ article.author }}</p>
Blog & Article

Current Blog Title

Outputs the name of the blog handle you are viewing (News, Journal, etc.).

When to use:blog.liquid listing page hero and meta sections.
<h1>{{ blog.title }}</h1>
<p>{{ blog.articles_count }} articles</p>
Blog & Article

Loop Articles on Blog Template

Standard loop when you are already on a blog listing template.

When to use:blog.liquid—use blog.articles instead of blogs['handle'].articles.
{% for article in blog.articles %}
  <article>
    <h2><a href="{{ article.url }}">{{ article.title }}</a></h2>
    <p>{{ article.excerpt | default: article.content | strip_html | truncate: 160 }}</p>
  </article>
{% endfor %}
Theme Settings

Global Theme Settings

Access settings defined in settings_schema.json (globally available).

When to use:For branding colors, typography choices, or global social media links.
{{ settings.color_primary }}
{{ settings.social_instagram_link }}
Theme Settings

Richtext Output

Outputs a richtext schema setting properly.

When to use:When you want merchants to be able to add bolding, italics, or links to text.
<div class="rte">
  {{ section.settings.text }}
</div>
Theme Settings

Select Setting Condition

Using a dropdown select setting to change layout logic.

When to use:For layout controls like text alignment or image positioning.
{% if section.settings.alignment == 'center' %}
  <div class="text-center">
{% else %}
  <div class="text-left">
{% endif %}
Theme Settings

Block Settings

Reads values from an individual block inside a section loop.

When to use:Sliders, FAQs, icon grids—any repeatable block defined in schema.
Read related guide →
{% for block in section.blocks %}
  <div {{ block.shopify_attributes }}>
    <h3>{{ block.settings.heading }}</h3>
    <p>{{ block.settings.text }}</p>
  </div>
{% endfor %}
Theme Settings

Image Picker Setting

Outputs an image from a section or block image_picker field.

When to use:Hero banners, logos, and background images controlled by merchants.
Read related guide →
{% if section.settings.image != blank %}
  {{ section.settings.image | image_url: width: 800 | image_tag: loading: 'lazy', alt: section.settings.image.alt | escape }}
{% endif %}
Theme Settings

Range Setting (Spacing)

Uses a numeric range value from schema—often for padding or font size.

When to use:When merchants need a slider control instead of typing raw pixel values.
Read related guide →
<div style="padding-top: {{ section.settings.padding }}px;">
  <!-- content -->
</div>
Theme Settings

Checkbox Toggle

Shows or hides elements based on a true/false schema checkbox.

When to use:Optional UI pieces—badges, secondary buttons, or extra metadata rows.
{% if section.settings.show_vendor %}
  <p class="product-card__vendor">{{ product.vendor }}</p>
{% endif %}
Theme Settings

Color Setting

Applies a merchant-selected color from the theme editor.

When to use:Section-level branding. Prefer CSS variables in theme settings for global palettes.
<div style="background-color: {{ section.settings.bg_color }};">
  {{ section.settings.heading }}
</div>
Theme Settings

URL Setting Link

Builds a CTA from a url-type schema setting.

When to use:Banner buttons, promo bars, and footer CTAs merchants can update without code.
{% if section.settings.button_link != blank %}
  <a href="{{ section.settings.button_link }}" class="btn">
    {{ section.settings.button_label | escape }}
  </a>
{% endif %}
Metafields

Product Metafield

Outputs a custom metafield attached to a product.

When to use:To display custom data like materials, sizing charts, or care instructions.
Read our Metafields Tutorial to learn how to create these in the admin.
{{ product.metafields.custom.care_instructions }}
Metafields

Render Rich Text Metafield

Safely renders HTML from a Rich Text Metafield.

When to use:If the metafield type is 'Rich text', you MUST use the metafield_tag filter to render it.
{{ product.metafields.custom.details | metafield_tag }}
Metafields

Check Metafield Before Output

Avoids empty wrappers when a metafield has no value.

When to use:Any optional custom field on product, collection, or article pages.
{% if product.metafields.custom.size_chart != blank %}
  <div class="size-chart">
    {{ product.metafields.custom.size_chart | metafield_tag }}
  </div>
{% endif %}
Metafields

Collection Metafield

Outputs custom data attached to a collection.

When to use:Extra collection copy, lookbook embeds, or merchandising notes below the title.
Read related guide →
{{ collection.metafields.custom.seo_intro }}
Metafields

Article Metafield

Displays custom fields on blog posts—reading time, series, etc.

When to use:Editorial blogs that need structured data beyond title and body.
{% if article.metafields.custom.reading_time != blank %}
  <span>{{ article.metafields.custom.reading_time }} min read</span>
{% endif %}
Metafields

Shop-Level Metafield

Reads metafields on the shop object for global theme data.

When to use:Store-wide banners or compliance text managed outside individual sections.
{{ shop.metafields.custom.announcement_text }}
Loops

For Loop with Limit

Loops exactly X number of times.

When to use:To show a preview of a collection, like a 'Featured Products' row.
{% for product in collection.products limit: 4 %}
  {{ product.title }}
{% endfor %}
Loops

Forloop Object (Index)

Access the current iteration number of a loop.

When to use:Useful for adding unique IDs or logic based on position (e.g. adding a 'active' class to the first slider dot).
{% for block in section.blocks %}
  Item number {{ forloop.index }} of {{ forloop.length }}
  {% if forloop.first %}This is the first!{% endif %}
  {% if forloop.last %}This is the last!{% endif %}
{% endfor %}
Loops

Loop with Offset

Skips the first N items—handy when the first product is featured elsewhere.

When to use:Homepage grids where item 1 is shown in a hero and items 2–5 fill a row.
Read related guide →
{% for product in collection.products limit: 4 offset: 1 %}
  {% render 'product-card', product: product %}
{% endfor %}
Loops

Reversed Loop

Iterates from last to first without mutating the original array.

When to use:Timelines, stacked cards, or any UI where newest content should appear first.
{% for block in section.blocks reversed %}
  {{ block.settings.heading }}
{% endfor %}
Loops

Assign Before Loop

Stores a collection or product in a variable for cleaner templates.

When to use:When the same list is referenced multiple times in one section.
{% assign featured_products = section.settings.collection.products %}
{% for product in featured_products limit: 8 %}
  {{ product.title }}
{% endfor %}
Loops

Tablerow for Grid Layouts

Opens and closes HTML rows every N columns automatically.

When to use:Legacy table-based grids. Most modern themes use CSS grid with a standard for loop instead.
<table>
  {% tablerow product in collection.products cols: 3 %}
    <td>{{ product.title }}</td>
  {% endtablerow %}
</table>
Conditions

If / Elsif / Else

Standard conditional logic.

When to use:Whenever you need to branch logic based on variables.
{% if product.price < 5000 %}
  Budget Friendly
{% elsif product.price < 10000 %}
  Mid-Range
{% else %}
  Premium
{% endif %}
Conditions

Unless (If Not)

The opposite of 'if'. Executes if the condition is false.

When to use:Cleaner to read than {% if product.available == false %}.
{% unless product.available %}
  Sold Out!
{% endunless %}
Conditions

Case / When

A switch statement for cleaner multiple-condition checks.

When to use:When checking a single variable against many possible values.
{% case section.settings.color_scheme %}
  {% when 'dark' %}
    <div class="bg-black text-white">
  {% when 'light' %}
    <div class="bg-white text-black">
  {% else %}
    <div class="bg-gray-100">
{% endcase %}
Conditions

Check if Blank

Liquid treats empty strings, false, and nil as falsy in conditionals.

When to use:Before rendering optional settings so you do not output empty headings or broken images.
{% if section.settings.heading != blank %}
  <h2>{{ section.settings.heading | escape }}</h2>
{% endif %}
Conditions

Contains Operator

Checks whether a string or array includes a value.

When to use:Tags, handles, and cart attribute-based feature flags.
{% if product.tags contains 'featured' %}
  <span class="badge">Featured</span>
{% endif %}

{% if cart.attributes['gift'] == 'yes' %}
  <!-- gift wrap UI -->
{% endif %}
Filters

Default Fallback

Provides a fallback value if the variable is blank.

When to use:To prevent empty spaces if a merchant deletes the text in a setting.
{{ section.settings.title | default: 'Welcome to our store' }}
Filters

Handleize

Converts a string into a URL-safe handle (lowercase, spaces to dashes).

When to use:Generating clean HTML IDs from titles.
{{ 'Hello World' | handleize }}
<!-- Outputs: hello-world -->
Filters

Replace & Split

String manipulation filters.

When to use:When manipulating text data, or turning comma-separated settings into arrays.
{{ 'I like apples' | replace: 'apples', 'oranges' }}

{% assign words = 'one,two,three' | split: ',' %}
{{ words[1] }} <!-- Outputs: two -->
Filters

Money Filter

Formats integers (cents) into localized currency strings.

When to use:Every price on the storefront. Prices in Liquid are stored in cents.
Read related guide →
{{ product.price | money }}
{{ cart.total_price | money_with_currency }}
{{ 2500 | money_without_trailing_zeros }}
Filters

image_url Filter

Builds a CDN URL for an image at a specific width (WebP when supported).

When to use:Any image output. Pair with image_tag for full responsive markup.
Warning: img_url is deprecated—always use image_url instead.
{{ product.featured_image | image_url: width: 600 }}
{{ section.settings.banner | image_url: width: 2000, height: 800, crop: 'center' }}
Filters

Escape Filter

Escapes HTML in plain text so user input cannot break your layout.

When to use:All plain text settings, alt attributes, and SEO meta fields.
Read related guide →
<h1>{{ section.settings.title | escape }}</h1>
<meta name="description" content="{{ page_description | escape }}">
Filters

Append & Prepend

Adds characters to the start or end of a string.

When to use:Building titles, tel: links, or breadcrumb labels without extra assign tags.
{{ product.title | append: ' | ' | append: shop.name }}
{{ section.settings.phone | prepend: 'tel:' }}
Filters

Truncate Text

Shortens long strings for cards and previews.

When to use:Blog cards, collection descriptions, and mobile-friendly teasers.
{{ article.excerpt | truncate: 120 }}
{{ product.description | strip_html | truncatewords: 25 }}
Filters

Strip HTML

Removes HTML tags from rich text for plain previews.

When to use:Search results and meta descriptions—not for full article bodies.
{{ article.content | strip_html | truncate: 200 }}
Snippets

Render Snippet

Includes a reusable Liquid file from the /snippets folder.

When to use:For separating SVG icons or reusable components (like product cards) from massive section files.
{% render 'icon-cart' %}
Snippets

Passing Variables to Snippets

Send data into a snippet.

When to use:Snippets cannot access variables defined outside of them unless explicitly passed in.
{% render 'product-card', product: current_product, show_vendor: true %}
Snippets

Snippet with For Loop

Keeps heavy markup in snippets while the section owns the loop.

When to use:Product grids shared across collection pages, search, and recommendations.
{% for product in collection.products limit: 4 %}
  {% render 'product-card', product: product, lazy: true %}
{% endfor %}
Snippets

Capture Snippet Output

Stores rendered HTML in a variable for reuse.

When to use:When you need the same snippet output twice or must inject it into JSON-LD.
{% capture card_html %}
  {% render 'product-card', product: product %}
{% endcapture %}
{{ card_html }}
Performance

Section Rendering API

Fetch just the HTML of a section without reloading the page.

When to use:When building ajax cart drawers or quick-view modals to save bandwidth.
Read related guide →
fetch('/?section_id=cart-drawer')
  .then(response => response.text())
  .then(html => console.log(html));
Performance

Lazy Load Images

Defers loading images below the fold until they are near the viewport.

When to use:Product grids, blog lists, and footer logos. Do not lazy-load the LCP hero image.
Read related guide →
{{ product.featured_image | image_url: width: 800 | image_tag: loading: 'lazy', decoding: 'async' }}
Performance

Responsive image_tag

Lets Shopify generate srcset and sizes for you.

When to use:Product and collection images on responsive layouts.
{{ product.featured_image | image_url: width: 1200 | image_tag:
  loading: 'lazy',
  sizes: '(min-width: 990px) 50vw, 100vw',
  widths: '375, 550, 750, 1100, 1500'
}}
Performance

Avoid Nested Loops

Deep nesting can hit Shopify Liquid render limits and slow TTFB.

When to use:Refactor to fewer loops, use limit, or move heavy logic to the Section Rendering API / app blocks.
Warning: If a page times out in the theme editor, check for triple-nested loops first.
{% comment %} Bad: loop inside loop inside loop {% endcomment %}
{% for collection in collections %}
  {% for product in collection.products %}
    {% for tag in product.tags %}
      ...
    {% endfor %}
  {% endfor %}
{% endfor %}
Performance

Paginate Large Lists

Shopify caps unpaginated product loops at 50 items.

When to use:Collection pages, large blogs, and customer order history lists.
{% paginate collection.products by 24 %}
  {% for product in collection.products %}
    {% render 'product-card', product: product %}
  {% endfor %}
{% endpaginate %}
Performance

Defer Non-Critical Scripts

Loads JavaScript after HTML parsing when possible.

When to use:Theme-wide JS that is not required for first paint.
<script src="{{ 'theme.js' | asset_url }}" defer></script>
{% if template.name == 'product' %}
  <script src="{{ 'product-form.js' | asset_url }}" defer></script>
{% endif %}
Schema

Basic Section Schema

The minimum required JSON to make a section editable.

When to use:At the bottom of every new section file. Without 'presets', it cannot be added via the Theme Editor.
{% schema %}
{
  "name": "Custom Banner",
  "settings": [],
  "presets": [
    {
      "name": "Custom Banner"
    }
  ]
}
{% endschema %}
Schema

Block Schema Definition

How to define blocks inside a section schema.

When to use:When building sliders, galleries, or lists where merchants need to add multiple items.
Read related guide →
"blocks": [
  {
    "type": "slide",
    "name": "Slide",
    "settings": [
      {
        "type": "image_picker",
        "id": "image",
        "label": "Image"
      }
    ]
  }
]
Schema

Text Setting in Schema

The most common setting type for headings and labels.

When to use:Any short string merchants should edit—titles, eyebrow text, button labels.
{
  "type": "text",
  "id": "heading",
  "label": "Heading",
  "default": "Shop our bestsellers"
}
Schema

Richtext Schema Setting

Lets merchants use bold, links, and lists in the theme editor.

When to use:Longer copy areas where basic text is too limiting.
{
  "type": "richtext",
  "id": "body",
  "label": "Body copy",
  "default": "<p>Tell your brand story here.</p>"
}
Schema

Range Schema Setting

Numeric slider with min, max, step, and unit.

When to use:Spacing, opacity, column counts—anything merchants should tune visually.
{
  "type": "range",
  "id": "padding_top",
  "min": 0,
  "max": 100,
  "step": 4,
  "unit": "px",
  "label": "Top padding",
  "default": 36
}
Schema

Select Schema Setting

Dropdown that drives layout or style variants in Liquid.

When to use:When merchants pick between a small set of predefined layouts.
{
  "type": "select",
  "id": "layout",
  "label": "Layout",
  "options": [
    { "value": "grid", "label": "Grid" },
    { "value": "carousel", "label": "Carousel" }
  ],
  "default": "grid"
}
Schema

Checkbox Schema Setting

Boolean toggle stored as true or false.

When to use:Optional UI elements merchants can turn on or off.
{
  "type": "checkbox",
  "id": "show_rating",
  "label": "Show star rating",
  "default": true
}
Schema

Schema Presets with Blocks

Pre-populates blocks when a merchant adds the section.

When to use:Demos and client handoffs—merchants see working content immediately.
Read related guide →
"presets": [
  {
    "name": "FAQ",
    "blocks": [
      { "type": "question" },
      { "type": "question" }
    ]
  }
]
Schema

Limit Blocks (max_blocks)

Caps how many blocks merchants can add to a section.

When to use:Strict layouts (e.g. exactly 4 columns) or performance-sensitive sections.
{
  "name": "Logo list",
  "max_blocks": 8,
  "blocks": [
    { "type": "logo", "name": "Logo" }
  ]
}
Schema

Schema Header Divider

Groups settings in the sidebar for easier editing.

When to use:Sections with many settings—keeps the theme editor scannable.
{
  "type": "header",
  "content": "Colors"
},
{
  "type": "color",
  "id": "text_color",
  "label": "Text color",
  "default": "#111111"
}