The official Liquid reference runs to hundreds of filters and tags. On a real theme I use about 40 of them, every day, across every store I touch. This is that short list, the Shopify Liquid you actually type, with copy-paste snippets and a one-page PDF you can pin next to your editor.
TL;DR: This is a working Shopify Liquid cheat sheet: prices with money, images with image_url, snippets with render, products with for, plus the objects and filters you reach for daily. Grab the free PDF below. Everything here is Shopify’s Liquid dialect, not standard open-source Liquid, so it runs on your theme as written.
Download the Liquid cheat sheet (PDF)
Why keep a Liquid cheat sheet at all
- The Liquid object reference is huge, but a theme edit usually needs six or seven of them, so a short list is faster than search.
- Most theme bugs I fix are small syntax slips:
moneyon a value that was already in cents,includewhererenderbelonged, aforloop with no pagination on a 900-product collection. - Getting these right the first time saves the round trip of push, preview, spot the mistake, push again, which is where theme time quietly goes.
How do you format a price in Shopify Liquid?
Use the money filter. Shopify stores every price in cents, so product.price of 1000 is ten dollars, and money handles the symbol and separators from your store’s currency settings.
{{ product.price | money }} {% comment %} $10.00 {% endcomment %}
{{ product.price | money_with_currency }} {% comment %} $10.00 USD {% endcomment %}
{{ product.price | money_without_trailing_zeros }}
{{ product.compare_at_price | money }} {% comment %} was-price {% endcomment %}
The rule I never break: no hardcoded $ in a theme, ever. A store that sells in more than one currency will show the wrong symbol the moment you do, and the money filter reference exists precisely so you do not have to. If you have hardcoded prices lurking in a theme, the multi-currency hardcoded price fix is the deeper read.
Which Liquid filters do you actually use?
A handful of string, math, and array filters cover most of what you write. They chain left to right with the pipe, so each filter takes the output of the one before it.
{{ 'HELLO' | downcase | capitalize }} {% comment %} Hello {% endcomment %}
{{ product.title | handleize }} {% comment %} url-safe handle {% endcomment %}
{{ product.description | strip_html | truncatewords: 30 }}
{{ item.line_price | divided_by: item.quantity | money }}
{{ product.tags | join: ', ' }}
{{ price | default: 0 | money }}
default is the quiet workhorse here: it swaps in a fallback when a value is empty or nil, which stops half your “why is this blank” bugs before they render. The full Liquid filter reference lists the rest, but these are the ones worth memorising.
How do you loop through products in Liquid?
The for tag walks any array. On collections, limit and offset page through, forloop gives you position, and an else branch handles the empty state cleanly.
{% for product in collection.products limit: 4 %}
{{ forloop.index }}. {{ product.title }} - {{ product.price | money }}
{% else %}
No products in this collection yet.
{% endfor %}
One thing that bites people on large stores: looping every product on a page is slow, and a collection with hundreds of items will drag your server response time. Wrap the loop in {% paginate collection.products by 24 %} and let Shopify render a page at a time. I dig into the numbers behind that in the Liquid loop optimization guide, and the break and continue reference covers early exits.
What is the difference between render, include, and section?
render pulls in a snippet with an isolated scope, so it only sees the variables you hand it. That isolation is the whole point: no accidental leaks from the parent template, no ghost variables, far fewer bugs.
{% render 'product-card', product: product, show_vendor: true %}
{% render 'price' for collection.products as product %}
{% section 'featured-collection' %}
{% sections 'footer-group' %}
include shares the parent scope and Shopify has deprecated it, so treat any include you find as tech debt and swap it for render. When you need to pass data in, named parameters on render keep the snippet contract explicit, and custom Liquid sections show the pattern on a full section.
How do you output an image without a raw CDN URL?
Never paste a cdn.shopify.com URL into a theme. Run the image through image_url with a width, and let image_tag build the responsive markup for you.
{{ product.featured_image | image_url: width: 800 }}
{{ product.featured_image
| image_url: width: 800
| image_tag: loading: 'lazy', alt: product.title }}
{{ image | image_url: width: 800, height: 800, crop: 'center' }}
A raw CDN URL locks you to one size and skips the responsive srcset that image_tag writes automatically, which hurts your Largest Contentful Paint. The width parameter is the one people forget, and it is what stops Shopify serving a 4000px original into a 400px slot.
The Liquid mistake I catch most on audits
Most theme performance problems are not the theme, they are a loop. I open a slow collection template and find a for loop over every product calling another for loop inside it, one lookup per item, no pagination. That nested pattern turns a 40ms render into a 400ms one, and no app caused it.
The fix is almost always a filter, not more code. where and map do in one line what a nested loop does in ten, and they run in Shopify’s engine instead of yours.
{% assign on_sale = collection.products | where: 'available' %}
{% assign titles = collection.products | map: 'title' %}
{{ collection.products.size }} {% comment %} count, no loop {% endcomment %}
I wrote up the real server cost of this in the true cost of Liquid loops. If your collection pages feel heavy, start there before you touch a single app.
Go deeper: the full Shopify Liquid cluster
This cheat sheet is the map. Each of these is the detailed walk-through when you hit the specific thing:
- The Shopify Liquid development guide is the pillar: setup, structure, and how themes fit together.
- Operator precedence: and vs or explains why your
ifwith mixed conditions evaluates the way it does. - The unless tag and comment syntax cover the small tags people misuse.
- Section schema setting types and reading custom metafields handle theme settings and stored data.
- Metaobjects vs metafields is the “which one do I use” call.
- Replacing apps with Liquid snippets and the no-app countdown timer show the cheat sheet applied to real features.
- The 250-variant cap fix and speed optimization in Liquid are the edge cases that catch growing stores.
How to use this cheat sheet this week
Three moves, none of which need a fresh theme.
- Download the PDF and keep it open in a split pane while you edit. Muscle memory beats tab-switching to the docs.
- Search your theme for
includeandcdn.shopify.com. Every hit is a quick, safe upgrade torenderandimage_url. - Open your slowest collection template and look for a loop inside a loop. That is usually the whole story.
Liquid is small once you stop trying to hold all of it. Keep the 40 you use in reach, and let the reference carry the rest.
The takeaway
- Format every price with
money, because Shopify stores prices in cents and hardcoded symbols break multi-currency. - Reach for
renderoverinclude, so snippets run in isolated scope and stop leaking variables. - Run images through
image_url: widthandimage_tag, never a raw CDN URL, to keep responsivesrcsetand LCP intact. - Paginate any loop over a large collection, and replace nested loops with
whereandmapto cut server time. - Pin the PDF, memorise the 40 filters and tags you use, and let the docs hold the long tail.
Kaspian Fuad is a Shopify developer and CRO consultant who builds and audits Liquid themes for DTC brands. 12 years in ecommerce, 100+ stores, Top Rated Plus on Upwork. Book a free 30-minute call if you want a theme audited for the loops and legacy tags quietly costing you speed.