Creating Variables with assign
Variables let you store intermediate values and keep templates readable. The {% assign %} tag creates a variable in the current scope. Liquid variables are dynamically typed — you do not declare types.
Allowed value types: strings, numbers, booleans, nil, arrays, and Liquid drops (Shopify objects). You cannot assign complex Ruby objects or execute functions with assign — only expressions.
{% assign greeting = "Hello" %}
{% assign on_sale = false %}
{% assign max_items = 4 %}
{% if customer %}
<p>{{ greeting }}, {{ customer.first_name }}!</p>
{% else %}
<p>{{ greeting }}, guest!</p>
{% endif %}capture — Store Rendered HTML
The {% capture %} tag executes everything inside it (including other Liquid tags and HTML), captures the resulting string, and stores it in a variable. This is essential for building HTML fragments you output in multiple places or pass to snippets.
{% capture sale_badge %}
{% if product.compare_at_price > product.price %}
<span class="badge badge--sale">
Save {{ product.compare_at_price | minus: product.price | money }}
</span>
{% endif %}
{% endcapture %}
{{ sale_badge }}Without capture, you would duplicate the if block everywhere you need the badge. Capture runs the inner template once and stores the result — including an empty string if the condition is false.
increment and decrement
These tags create a counter variable in the parent scope, starting at 0. Each call to {% increment var %} returns the current value then adds 1. Useful for zebra-striping rows without manual index math.
{% for item in cart.items %}
<tr class="row-{% increment row_counter %}">
<td>{{ item.product.title }}</td>
</tr>
{% endfor %}