Developers · Liquid
Liquid Tags: Loops
Last updated 2 November 2026
This article discusses the following topics:
- for
- cycle
- ifchanged
- tablerow
for
Liquid allows
Iterating Over an Array
{% for item in array %}
{{ item }}
{% endfor %}Iterating Over a Hash
When iterating a hash, item[0] contains the key, and item[1] contains the value:
{% for item in hash %}
{{ item[0] }}: {{ item[1] }}
{% endfor %}
Instead of looping over an existing collection, you can also loop through a range of numbers.
Ranges look like
Input if item.quantity is 4
{% for i in (1..item.quantity) %}
{{ i }}
{% endfor %}Output
1,2,3,4Breaking and Continuing
You can exit a loop early with the following tags:
: immediately end the current iteration, and continue the loop with the next value. : immediately end the current iteration, then completely end the loop.
These are only useful when combined with an
{% for page in pages %}
{% comment %}
Skip anything in the hidden_pages array,
but keep looping over the rest of the values
{% endcomment %}
{% if hidden_pages contains page.url %}
{% continue %}
{% endif %}
{% comment %} If it's not hidden, print it. {% endcomment %}
* [page.title](page.url)
{% endfor %}{% for page in pages %}
* [page.title](page.url)
{% comment %}
After we reach the "cutoff" page,
stop the list and get on with whatever's after the "for" loop:
{% endcomment %}
{% if cutoff_page == page.url %}
{% break %}
{% endif %}
{% endfor %}Helper Variables
During every
| Variable | Description |
|---|---|
| forloop.length | The length of the entire for loop. |
| forloop.index | The index of the current iteration. |
| forloop.index0 | The index of the current iteration (zero-based). |
| forloop.rindex | Returns number of remaining items. |
| forloop.rindex0 | Returns number of remaining items (zero-based). |
| forloop.first | Is this the first iteration? |
| forloop.last | Is this the last iteration? |
| forloop.parentloop | Provides access to the parent loop, if present. |
Find examples on the Liquid Objects page.
Optional Arguments
There are several optional arguments to the
lets you restrict how many items you get. lets you start the collection with the nth item. iterates over the collection from last to first.
Restricting Elements
array = [1,2,3,4,5,6]
{% for item in array limit:2 offset:2 %}
{{ item }}
{% endfor %}Output
3,4Reversing the Loop
{% for item in collection reversed %}
{{ item }}
{% endfor %}Handling an Empty Collection
A
items => []
{% for item in items %}
{{ item.title }}
{% else %}
There are no items!
{% endfor %}cycle
Loops through a group of strings and outputs them in the order that they were passed as parameters. Each time
{% for i in (1..4) -%}
{% cycle "one", "two", "three" %}
{% endfor -%}will result in:
one
two
three
oneThough
{% cycle "one", "two", "three" %}
{% cycle "banana", "apple", "orange" %}
{% cycle "one", "two", "three" %}
{% cycle "one", "two", "three" %}will result in:
one
apple
three
oneIf you want total control over
{% cycle "group 1": "one", "two", "three", "four" %}
{% cycle "group 1": "one", "two", "three", "four" %}
{% cycle "group 2": "one", "two", "three", "four" %}
{% cycle "group 2": "one", "two", "three", "four" %}
{% cycle "group 1": "one", "two", "three", "four" %}
{% cycle "group 1": "one", "two", "three", "four" %}will result in:
one
two
one
two
three
fourLiquid assumes that each
{% cycle "A", "B", "C", "D" %}
{% cycle "group 3": "one", "two", "three", "four" %}
{% cycle "group 4": "one", "two", "three", "four" %}
{% cycle "group 4": "one", "two", "three", "four" %}
{% cycle "group 3": "one", "two", "three", "four" %}
{% cycle "group 3": "one", "two", "three", "four" %}
{% cycle "A", "B", "C", "D" %}will result in:
A
one
one
two
two
three
Bifchanged
The
Input
{% assign list = "1,1,1,1,3,3,3,2,1,3,1,2" | split: "," %}
{% for item in list -%}
{%- ifchanged %} {{ item }} {% endifchanged -%}
{%- endfor %}Output
1 3 2 1 3 1 2tablerow
Generates rows for an HTML table. Must be wrapped in opening
<table>
{% tablerow product in collection.products %}
{{ product.title }}
{% endtablerow %}
</table><table>
<tr class="row1">
<td class="col1">Cool Shirt</td>
<td class="col2">Alien Poster</td>
<td class="col3">Batman Poster</td>
<td class="col4">Bullseye Shirt</td>
<td class="col5">Another Classic Vinyl</td>
<td class="col6">Awesome Jeans</td>
</tr>
</table>tablerow tag parameters
cols
Defines how many columns the tables should have.
Input
<table>
{% tablerow product in collection.products cols:2 %}
{{ product.title }}
{% endtablerow %}
</table>Output
<table>
<tr class="row1">
<td class="col1">Cool Shirt</td>
<td class="col2">Alien Poster</td>
</tr>
<tr class="row2">
<td class="col1">Batman Poster</td>
<td class="col2">Bullseye Shirt</td>
</tr>
<tr class="row3">
<td class="col1">Another Classic Vinyl</td>
<td class="col2">Awesome Jeans</td>
</tr>
</table>limit
Exits the
{% tablerow product in collection.products cols:2 limit:3 %}
{{ product.title }}
{% endtablerow %}offset
Starts the
{% tablerow product in collection.products cols:2 offset:3 %}
{{ product.title }}
{% endtablerow %}range
Defines a range of numbers to loop through. Both literal and variable numbers can define the range.
<table>
{% tablerow i in (3..5) %}
{{ i }}
{% endtablerow %}
</table>
{% assign num = 4 %}
<table>
{% tablerow i in (1..num) %}
{{ i }}
{% endtablerow %}
</table>Note
This topic is a compilation of knowledge found at Shopify Themes, Liquid Documentation, Liquid Gem Documentation, and Liquid for Designers.
Try it
Edit the input and press Run. The example runs on this site, read-only.