Liquid is "a template language created by Shopify", open source on GitHub and used well beyond Shopify1. Shopify co-founder and CEO Tobias Lütke developed it4. The version your theme runs "extends the open-source version of Liquid" with the tags, filters and objects a store needs1.
The first part of this page defines Liquid. The rest is a cheat sheet of the tags, filters and objects that show up in almost every theme, each one checked against shopify.dev on 16 September 2026, along with the documented limits that break themes in production.
§01Definition
Definition
Liquid is the template language Shopify created and every Shopify theme is written in. It mixes HTML with three building blocks: objects that output store data, tags that add logic, and filters that change output. Liquid is open source, and Shopify themes run an extended version of it.
The GitHub project calls it a "safe, customer facing template language for flexible web apps"3, and the README says it had to be "non evaling and secure". That design choice is why Shopify can let merchants and developers edit templates on its own servers: a Liquid template can read store data and loop over it, but it can't run arbitrary code.
Shopify runs slightly different Liquid variants in notification templates, Shopify Flow, and order printer and packing slip templates. The theme reference, and this cheat sheet, cover theme Liquid only1.
§02Syntax
How Liquid works
Output goes in double curly braces, logic goes in curly-brace-percent tags, and filters follow a pipe character. A hyphen inside either delimiter strips the whitespace Liquid would otherwise leave in the HTML.
Liquid has six data types: string, number, boolean, nil, array and empty. The comparison operators are ==, !=, >, <, >= and <=, and the logical ones are or, and and contains2.
Two rules surprise people coming from other languages. Only nil and false are falsy, so an empty string counts as true. And when a tag has more than one operator, Liquid evaluates them right to left, with no parentheses to change the order2.
§03Tags
Liquid cheat sheet: tags
Tags hold the logic. These are the ones a Shopify theme uses constantly, with the syntax shopify.dev documents.
Tag
Syntax
What it does
if / elsif / else
{% if cond %}…{% elsif other %}…{% else %}…{% endif %}
Conditional output
unless
{% unless cond %}…{% endunless %}
Renders unless the condition is true. Accepts elsif too
case / when
{% case x %}{% when 'a' %}…{% else %}…{% endcase %}
Switch on a value
for
{% for item in array limit: 4 %}…{% endfor %}
Loops an array or a range (1..5). Also offset and reversed. Stops at 50 iterations5
paginate
{% paginate collection.products by 24 %}…{% endpaginate %}
Splits an array across pages, 1 to 250 items per page6
assign
{% assign name = value %}
Creates a variable
capture
{% capture name %}…{% endcapture %}
Creates a string variable from a block of output
render
{% render 'snippet' with product as item %}
Renders a snippet or app block in its own variable scope7
section
{% section 'header' %}
Renders a section statically
sections
{% sections 'header-group' %}
Renders a section group
content_for
{% content_for 'blocks' %}
Where theme blocks render. A single static block needs type and id
liquid
{% liquid … %}
Many tags inside one delimiter, one tag per line. Output with echo (example below)
comment
{% comment %}…{% endcomment %} or {% # note %}
Code that is parsed but never rendered
doc
{% doc %} @param {string} title {% enddoc %}
LiquidDoc annotations for tooling. Not rendered
form
{% form 'localization' %}…{% endform %}
Outputs a Shopify form, such as the country and language selector
The liquid tag is the one that most cleans up a messy snippet. Shopify's own example:
LiquidThe liquid tag, from shopify.dev
{% liquid
assign product_type = product.type | downcase
assign message = ''
case product_type
when 'health'
assign message = 'This is a health potion!'
when 'love'
assign message = 'This is a love potion!'
else
assign message = 'This is a potion!'
endcase
echo message
%}
§04Filters
Liquid cheat sheet: filters
Filters change what an object outputs. They chain left to right after a pipe, and several take named parameters after a colon.
Filter
Example
What it does
money family
{{ product.price | money }}
Formats a price with the store's currency format. Also money_with_currency, money_without_currency, money_without_trailing_zeros
image_url
{{ product | image_url: width: 800 }}
CDN URL for an image. Needs width or height, max 5760 px, never upscales9
image_tag
{{ product | image_url: width: 800 | image_tag }}
Full <img> with width, height, srcset, and lazy loading below the fold
Fallback when a value is empty, false or nil. allow_false: true keeps false
escape
{{ product.title | escape }}
HTML-escapes <, >, quotes and &
handleize
{{ product.title | handleize }}
Turns "Health potion" into health-potion. Alias handle
date
{{ article.created_at | date: '%B %d, %Y' }}
strftime formatting. 'now' gives the render time, format: 'abbreviated_date' a locale-aware one
where
{{ collection.products | where: 'available' }}
Keeps array items whose property matches, or is true
For images, image_url plus image_tag is the pair to use: it's the route through which Shopify serves modern formats, covered in AVIF and WebP on Shopify. The old img_url filter is deprecated9.
§05Objects
Liquid cheat sheet: objects
Objects hold the store's data. Some are global, some only exist on the template that owns them, like product on a product page.
Object
Common properties
Notes
product
title, price, compare_at_price, variants, available
Prices are in the currency's subunit, in the shopper's local currency11
collection
products
Paginate collection.products to get past 50 items
cart
total_price, item_count, items, currency
total_price is after discounts, in subunits
shop
name, currency, money_format, enabled_currencies
shop.currency is the base currency, not the shopper's
settings
Any theme setting, e.g. settings.currency_code_enable
Values from the theme editor, defined in config/
routes
root_url, cart_url, search_url, collections_url
Locale-aware URLs. Use them instead of hard-coding /cart
Shopify's required scripts. Goes in <head>. Don't parse or modify it
content_for_layout
(none)
The current template's content. Goes in <body> of theme.liquid
§06Gotchas
Liquid limits and gotchas
Most Liquid bugs on Shopify trace back to a short list of documented limits. A for loop stops at 50 items, snippets can't see outside variables, and prices are integers in cents.
A for loop runs at most 50 times. For more, wrap it in paginate, which allows 1 to 250 items per page and stops at the 25,000th item56. Paginated collections are where Shopify's ?page=N collection URLs come from.
render isolates variables in both directions. A snippet can't read a variable you assigned in the section that calls it, so pass it in with with or for7.
include is deprecated because of how it handles variables, and you can't use it inside a snippet that was called with render7.
image_url returns an error if you give it neither a width nor a height9.
Prices are integers in the currency's subunit: 1000 is $10.00, and 1000 yen arrives as 100000. Format them with the money filters rather than dividing by hand11.
An empty string is truthy. After {% assign note = '' %}, the test {% if note %} still passes. Compare against empty when a value can be blank.
assign can overwrite a global object if you reuse its name. Don't call a variable product or cart.
The json filter leaves out a variant's inventory_quantity and inventory_policy on stores created after 5 December 201710, so a script that expects stock counts in {{ product | json }} gets nothing.
§07Where it lives
Where Liquid lives in a Shopify theme
Only one file is required: layout/theme.liquid. Everything else in a theme sits in eight folders: assets, blocks, config, layout, locales, sections, snippets and templates.
Templates can be JSON or Liquid. A JSON template only wraps sections, while a Liquid template contains code12. In a theme built on JSON templates, the Liquid itself sits in sections, blocks and snippets. robots.txt.liquid is the notable exception: it has to stay a Liquid template.
For SEO, the Liquid you touch most sits in the <head> of theme.liquid: meta robots rules (see noindex in theme.liquid) and site-wide JSON-LD (see custom JSON-LD via theme.liquid). Liquid renders on Shopify's servers, so everything it outputs is in the HTML crawlers receive, including crawlers that don't run JavaScript.
§08Related
Related terms
Liquid is the layer where most Shopify SEO fixes are actually written.