Developer reference
Shopify Liquid Cheat Sheet
Interactive quick reference for tags, filters, objects, and schema. Search or browse by category.
Most used
Render Section Setting
Outputs a text or basic setting value from the section schema.
{{ section.settings.title }}Render Image (Modern)
The modern, performant way to render an image picker setting with automatic WebP support.
{{ section.settings.image | image_url: width: 800 | image_tag: loading: 'lazy', class: 'my-custom-class' }}Basic For Loop
Loops through section blocks to render repeated content like a gallery or FAQ.
{% for block in section.blocks %}
<div {{ block.shopify_attributes }}>
{{ block.settings.heading }}
</div>
{% endfor %}All snippets
Render Section Setting
Outputs a text or basic setting value from the section schema.
{{ section.settings.title }}Render Image (Modern)
The modern, performant way to render an image picker setting with automatic WebP support.
{{ section.settings.image | image_url: width: 800 | image_tag: loading: 'lazy', class: 'my-custom-class' }}Basic For Loop
Loops through section blocks to render repeated content like a gallery or FAQ.
{% for block in section.blocks %}
<div {{ block.shopify_attributes }}>
{{ block.settings.heading }}
</div>
{% endfor %}Product Title
Outputs the title of the current product.
{{ product.title }}Product Price Formatting
Formats the product price according to the store's currency settings.
{{ product.price | money }}
<!-- Compare at price -->
{{ product.compare_at_price | money }}Product Vendor & Type
Outputs the vendor (brand) and product type.
{{ product.vendor }}
{{ product.type }}Product Tags Loop
Iterates through all tags attached to a product.
{% for tag in product.tags %}
<span class="badge">{{ tag }}</span>
{% endfor %}First Available Variant
Gets the first variant that is currently in stock.
{% assign current_variant = product.selected_or_first_available_variant %}
{{ current_variant.price | money }}Product Media Gallery
Loops through all images, videos, and 3D models attached to a product.
{% for media in product.media %}
{% render 'media', media: media %}
{% endfor %}Product Description
Outputs the main product description HTML from the admin.
<div class="product-description rte">
{{ product.description }}
</div>Product Description (Plain Preview)
Strips HTML tags for short previews in cards or search results.
{{ product.description | strip_html | truncate: 120 }}Product URL
The canonical URL path for the current product.
<a href="{{ product.url }}">{{ product.title }}</a>Check Product Availability
Returns true if at least one variant can be purchased.
{% if product.available %}
<button type="submit" name="add">Add to cart</button>
{% else %}
<button disabled>Sold out</button>
{% endif %}Featured Product Image
Renders the product's main image using modern Shopify image filters.
{% if product.featured_image %}
{{ product.featured_image | image_url: width: 1200 | image_tag: loading: 'eager', alt: product.featured_image.alt | escape }}
{% endif %}Featured Media (OS 2.0)
Accesses the primary media object, which may be an image, video, or 3D model.
{% if product.featured_media %}
{% render 'product-media', media: product.featured_media %}
{% endif %}Loop All Variants
Iterates every variant (size, color, etc.) on a product.
{% for variant in product.variants %}
<option value="{{ variant.id }}" {% unless variant.available %}disabled{% endunless %}>
{{ variant.title }} — {{ variant.price | money }}
</option>
{% endfor %}Variant SKU & Barcode
Outputs inventory identifiers for the selected or first available variant.
{% assign v = product.selected_or_first_available_variant %}
<p>SKU: {{ v.sku }}</p>
<p>Barcode: {{ v.barcode }}</p>Product Options (Size, Color)
Loops option names and values—for example Color: Red, Blue.
{% 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 %}Check for Specific Tag
Shows content only when a product has a given tag.
{% if product.tags contains 'sale' %}
<span class="badge badge--sale">On sale</span>
{% endif %}Collection Title & Description
Outputs the collection's title and its rich text description.
<h1>{{ collection.title }}</h1>
<div>{{ collection.description }}</div>Loop Collection Products
Iterates through products in a specific collection.
{% for product in collection.products %}
<h2>{{ product.title }}</h2>
{% else %}
<p>No products found.</p>
{% endfor %}Paginate Collection
Required for collections with more than 50 products.
{% paginate collection.products by 12 %}
{% for product in collection.products %}
<!-- Render product card -->
{% endfor %}
{{ paginate | default_pagination }}
{% endpaginate %}Collection URL & Handle
Builds links and CSS hooks from the collection object.
<a href="{{ collection.url }}">{{ collection.title }}</a>
<!-- Handle for data attributes -->
data-collection="{{ collection.handle }}"Collection Product Count
Shows how many products belong to the collection.
<p>{{ collection.products_count }} products</p>Collection Featured Image
Renders the image uploaded for the collection in the admin.
{% if collection.image %}
{{ collection.image | image_url: width: 1600 | image_tag: loading: 'lazy', alt: collection.title | escape }}
{% endif %}Collection from Section Setting
Loops products from a collection the merchant picked in the theme editor.
{% assign featured = section.settings.collection %}
{% if featured != blank %}
{% for product in featured.products limit: section.settings.limit %}
{% render 'product-card', product: product %}
{% endfor %}
{% endif %}Paginate Blog Articles
Pagination works for blogs too—not only collections.
{% 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 Item Count & Total
Displays the total number of items and the total price of the cart.
{{ cart.item_count }} items
{{ cart.total_price | money_with_currency }}Cart Items Loop
Loops through all items currently in the cart.
{% 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 %}Empty Cart Check
Shows different markup when the cart has zero items.
{% 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 Subtotal vs Total
Displays line totals; cart.total_price includes discounts where applicable.
<p>Subtotal: {{ cart.total_price | money }}</p>
<p>Items: {{ cart.item_count }}</p>Line Item Variant Title
Shows the variant name (e.g. Size M / Color Black) for each cart line.
{% for item in cart.items %}
<p class="line-item__variant">{{ item.variant.title }}</p>
{% endfor %}Line Item Properties
Outputs custom properties added at add-to-cart (engraving, gift message, etc.).
{% 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 Note Field
Outputs the optional note customers leave for the store.
<textarea name="note">{{ cart.note }}</textarea>Check if Logged In
Checks if a customer is currently logged into their account.
{% 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 Full Name
Outputs first and last name, or a combined name when available.
{{ customer.name }}
<!-- Or separately -->
{{ customer.first_name }} {{ customer.last_name }}Customer Account Links
Uses Shopify route objects for correct login, register, and logout URLs.
<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 Email & Orders
Shows account email and loops recent orders on the account page.
<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 %}Default Customer Address
Outputs the customer's default shipping address when set.
{% 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 Articles Loop
Loops through articles in a specific blog (e.g., 'news').
{% 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 %}Article Title & URL
Standard article heading and permalink on article templates.
<h1>{{ article.title }}</h1>
<p><time datetime="{{ article.published_at | date: '%Y-%m-%d' }}">{{ article.published_at | date: format: 'abbreviated_date' }}</time></p>Article Content
Outputs the full article body HTML from the blog editor.
<div class="article-content rte">
{{ article.content }}
</div>Article Author & Image
Shows byline and featured image when present.
{% if article.image %}
{{ article.image | image_url: width: 1200 | image_tag: loading: 'lazy', alt: article.title | escape }}
{% endif %}
<p>By {{ article.author }}</p>Current Blog Title
Outputs the name of the blog handle you are viewing (News, Journal, etc.).
<h1>{{ blog.title }}</h1>
<p>{{ blog.articles_count }} articles</p>Loop Articles on Blog Template
Standard loop when you are already on a blog listing template.
{% 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 %}Global Theme Settings
Access settings defined in settings_schema.json (globally available).
{{ settings.color_primary }}
{{ settings.social_instagram_link }}Richtext Output
Outputs a richtext schema setting properly.
<div class="rte">
{{ section.settings.text }}
</div>Select Setting Condition
Using a dropdown select setting to change layout logic.
{% if section.settings.alignment == 'center' %}
<div class="text-center">
{% else %}
<div class="text-left">
{% endif %}Block Settings
Reads values from an individual block inside a section loop.
{% for block in section.blocks %}
<div {{ block.shopify_attributes }}>
<h3>{{ block.settings.heading }}</h3>
<p>{{ block.settings.text }}</p>
</div>
{% endfor %}Image Picker Setting
Outputs an image from a section or block image_picker field.
{% if section.settings.image != blank %}
{{ section.settings.image | image_url: width: 800 | image_tag: loading: 'lazy', alt: section.settings.image.alt | escape }}
{% endif %}Range Setting (Spacing)
Uses a numeric range value from schema—often for padding or font size.
<div style="padding-top: {{ section.settings.padding }}px;">
<!-- content -->
</div>Checkbox Toggle
Shows or hides elements based on a true/false schema checkbox.
{% if section.settings.show_vendor %}
<p class="product-card__vendor">{{ product.vendor }}</p>
{% endif %}Color Setting
Applies a merchant-selected color from the theme editor.
<div style="background-color: {{ section.settings.bg_color }};">
{{ section.settings.heading }}
</div>URL Setting Link
Builds a CTA from a url-type schema setting.
{% if section.settings.button_link != blank %}
<a href="{{ section.settings.button_link }}" class="btn">
{{ section.settings.button_label | escape }}
</a>
{% endif %}Product Metafield
Outputs a custom metafield attached to a product.
{{ product.metafields.custom.care_instructions }}Render Rich Text Metafield
Safely renders HTML from a Rich Text Metafield.
{{ product.metafields.custom.details | metafield_tag }}Check Metafield Before Output
Avoids empty wrappers when a metafield has no value.
{% if product.metafields.custom.size_chart != blank %}
<div class="size-chart">
{{ product.metafields.custom.size_chart | metafield_tag }}
</div>
{% endif %}Collection Metafield
Outputs custom data attached to a collection.
{{ collection.metafields.custom.seo_intro }}Article Metafield
Displays custom fields on blog posts—reading time, series, etc.
{% if article.metafields.custom.reading_time != blank %}
<span>{{ article.metafields.custom.reading_time }} min read</span>
{% endif %}Shop-Level Metafield
Reads metafields on the shop object for global theme data.
{{ shop.metafields.custom.announcement_text }}For Loop with Limit
Loops exactly X number of times.
{% for product in collection.products limit: 4 %}
{{ product.title }}
{% endfor %}Forloop Object (Index)
Access the current iteration number of a loop.
{% 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 %}Loop with Offset
Skips the first N items—handy when the first product is featured elsewhere.
{% for product in collection.products limit: 4 offset: 1 %}
{% render 'product-card', product: product %}
{% endfor %}Reversed Loop
Iterates from last to first without mutating the original array.
{% for block in section.blocks reversed %}
{{ block.settings.heading }}
{% endfor %}Assign Before Loop
Stores a collection or product in a variable for cleaner templates.
{% assign featured_products = section.settings.collection.products %}
{% for product in featured_products limit: 8 %}
{{ product.title }}
{% endfor %}Tablerow for Grid Layouts
Opens and closes HTML rows every N columns automatically.
<table>
{% tablerow product in collection.products cols: 3 %}
<td>{{ product.title }}</td>
{% endtablerow %}
</table>If / Elsif / Else
Standard conditional logic.
{% if product.price < 5000 %}
Budget Friendly
{% elsif product.price < 10000 %}
Mid-Range
{% else %}
Premium
{% endif %}Unless (If Not)
The opposite of 'if'. Executes if the condition is false.
{% unless product.available %}
Sold Out!
{% endunless %}Case / When
A switch statement for cleaner multiple-condition checks.
{% 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 %}Check if Blank
Liquid treats empty strings, false, and nil as falsy in conditionals.
{% if section.settings.heading != blank %}
<h2>{{ section.settings.heading | escape }}</h2>
{% endif %}Contains Operator
Checks whether a string or array includes a value.
{% if product.tags contains 'featured' %}
<span class="badge">Featured</span>
{% endif %}
{% if cart.attributes['gift'] == 'yes' %}
<!-- gift wrap UI -->
{% endif %}Default Fallback
Provides a fallback value if the variable is blank.
{{ section.settings.title | default: 'Welcome to our store' }}Handleize
Converts a string into a URL-safe handle (lowercase, spaces to dashes).
{{ 'Hello World' | handleize }}
<!-- Outputs: hello-world -->Replace & Split
String manipulation filters.
{{ 'I like apples' | replace: 'apples', 'oranges' }}
{% assign words = 'one,two,three' | split: ',' %}
{{ words[1] }} <!-- Outputs: two -->Money Filter
Formats integers (cents) into localized currency strings.
{{ product.price | money }}
{{ cart.total_price | money_with_currency }}
{{ 2500 | money_without_trailing_zeros }}image_url Filter
Builds a CDN URL for an image at a specific width (WebP when supported).
{{ product.featured_image | image_url: width: 600 }}
{{ section.settings.banner | image_url: width: 2000, height: 800, crop: 'center' }}Escape Filter
Escapes HTML in plain text so user input cannot break your layout.
<h1>{{ section.settings.title | escape }}</h1>
<meta name="description" content="{{ page_description | escape }}">Append & Prepend
Adds characters to the start or end of a string.
{{ product.title | append: ' | ' | append: shop.name }}
{{ section.settings.phone | prepend: 'tel:' }}Truncate Text
Shortens long strings for cards and previews.
{{ article.excerpt | truncate: 120 }}
{{ product.description | strip_html | truncatewords: 25 }}Strip HTML
Removes HTML tags from rich text for plain previews.
{{ article.content | strip_html | truncate: 200 }}Render Snippet
Includes a reusable Liquid file from the /snippets folder.
{% render 'icon-cart' %}Passing Variables to Snippets
Send data into a snippet.
{% render 'product-card', product: current_product, show_vendor: true %}Snippet with For Loop
Keeps heavy markup in snippets while the section owns the loop.
{% for product in collection.products limit: 4 %}
{% render 'product-card', product: product, lazy: true %}
{% endfor %}Capture Snippet Output
Stores rendered HTML in a variable for reuse.
{% capture card_html %}
{% render 'product-card', product: product %}
{% endcapture %}
{{ card_html }}Section Rendering API
Fetch just the HTML of a section without reloading the page.
fetch('/?section_id=cart-drawer')
.then(response => response.text())
.then(html => console.log(html));Lazy Load Images
Defers loading images below the fold until they are near the viewport.
{{ product.featured_image | image_url: width: 800 | image_tag: loading: 'lazy', decoding: 'async' }}Responsive image_tag
Lets Shopify generate srcset and sizes for you.
{{ product.featured_image | image_url: width: 1200 | image_tag:
loading: 'lazy',
sizes: '(min-width: 990px) 50vw, 100vw',
widths: '375, 550, 750, 1100, 1500'
}}Avoid Nested Loops
Deep nesting can hit Shopify Liquid render limits and slow TTFB.
{% 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 %}Paginate Large Lists
Shopify caps unpaginated product loops at 50 items.
{% paginate collection.products by 24 %}
{% for product in collection.products %}
{% render 'product-card', product: product %}
{% endfor %}
{% endpaginate %}Defer Non-Critical Scripts
Loads JavaScript after HTML parsing when possible.
<script src="{{ 'theme.js' | asset_url }}" defer></script>
{% if template.name == 'product' %}
<script src="{{ 'product-form.js' | asset_url }}" defer></script>
{% endif %}Basic Section Schema
The minimum required JSON to make a section editable.
{% schema %}
{
"name": "Custom Banner",
"settings": [],
"presets": [
{
"name": "Custom Banner"
}
]
}
{% endschema %}Block Schema Definition
How to define blocks inside a section schema.
"blocks": [
{
"type": "slide",
"name": "Slide",
"settings": [
{
"type": "image_picker",
"id": "image",
"label": "Image"
}
]
}
]Text Setting in Schema
The most common setting type for headings and labels.
{
"type": "text",
"id": "heading",
"label": "Heading",
"default": "Shop our bestsellers"
}Richtext Schema Setting
Lets merchants use bold, links, and lists in the theme editor.
{
"type": "richtext",
"id": "body",
"label": "Body copy",
"default": "<p>Tell your brand story here.</p>"
}Range Schema Setting
Numeric slider with min, max, step, and unit.
{
"type": "range",
"id": "padding_top",
"min": 0,
"max": 100,
"step": 4,
"unit": "px",
"label": "Top padding",
"default": 36
}Select Schema Setting
Dropdown that drives layout or style variants in Liquid.
{
"type": "select",
"id": "layout",
"label": "Layout",
"options": [
{ "value": "grid", "label": "Grid" },
{ "value": "carousel", "label": "Carousel" }
],
"default": "grid"
}Checkbox Schema Setting
Boolean toggle stored as true or false.
{
"type": "checkbox",
"id": "show_rating",
"label": "Show star rating",
"default": true
}Schema Presets with Blocks
Pre-populates blocks when a merchant adds the section.
"presets": [
{
"name": "FAQ",
"blocks": [
{ "type": "question" },
{ "type": "question" }
]
}
]Limit Blocks (max_blocks)
Caps how many blocks merchants can add to a section.
{
"name": "Logo list",
"max_blocks": 8,
"blocks": [
{ "type": "logo", "name": "Logo" }
]
}Schema Header Divider
Groups settings in the sidebar for easier editing.
{
"type": "header",
"content": "Colors"
},
{
"type": "color",
"id": "text_color",
"label": "Text color",
"default": "#111111"
}