Writing Liquid
Variables, filters, loops, and conditionals — the basics of Storra's templating language.
Storra themes use Liquid, a template language that mixes HTML markup with placeholders for dynamic content. If you've never used a template language before, the mental model is simple: write HTML normally, drop in {{ ... }} wherever you want to insert a value, and use {% ... %} for control flow like loops and conditionals.
The two delimiters
Output: {{ value }}
Anything between double curly braces is evaluated and printed into the page. Variables, calculations, formatted strings.
<h1>{{ store.name }}</h1>
<p>Welcome to our store!</p>
Tags: {% statement %}
Anything between curly-brace-percent is a control statement — loops, conditionals, includes, variable assignments. Doesn't print anything itself.
{% if customer %}
<p>Welcome back, {{ customer.first_name }}!</p>
{% endif %}
Common variables
Every template has access to a set of variables Storra populates automatically:
store— your store's metadata (name, currency, logo URL).packages— the catalog. On templates that scope to a category or search, this is filtered.package— on a product template, the specific package being viewed.customer— the signed-in customer, ornullif no one is signed in.cart— the current basket and its contents.section— inside a section file, the section's own settings and blocks.request— page-level info: locale, current path, query parameters.
Filters: transforming values
Use the pipe | to transform a value. Common filters:
{{ "hello" | upcase }} ← "HELLO"
{{ 999 | format_money }} ← "$9.99"
{{ package.image_url | image_url: "640x" }} ← resized image
{{ "now" | date: "%Y" }} ← "2026"
{{ section.settings.html | escape }} ← HTML-safe
Filters can chain — the output of one becomes the input of the next.
Loops
Iterate over a collection with {% for %}.
{% for package in packages limit: 12 %}
<a href="{{ package.url }}">
<img src="{{ package.image_url | image_url: '320x' }}" alt="">
<h3>{{ package.name }}</h3>
<span>{{ package.price | format_money }}</span>
</a>
{% endfor %}
Add limit:, offset:, or reversed to constrain the loop.
Conditionals
Branch with {% if %}.
{% if store.currency == "USD" %}
<p>Prices in US Dollars</p>
{% elsif store.currency == "EUR" %}
<p>Prices in Euros</p>
{% else %}
<p>Prices in {{ store.currency }}</p>
{% endif %}
Variables
Define your own with {% assign %}.
{% assign featured = packages | where: "featured", true %}
<h2>Featured packages</h2>
{% for pkg in featured %}
<p>{{ pkg.name }}</p>
{% endfor %}
Section settings
Inside a section file, section.settings exposes whatever the merchant configured in the visual editor.
<h2>{{ section.settings.heading }}</h2>
<p style="color: {{ section.settings.text_color }};">
{{ section.settings.body }}
</p>
For sections with blocks, section.blocks is the array of merchant-added blocks. Loop through them and render each:
{% for block in section.blocks %}
<div class="feature">
<img src="{{ block.settings.icon | asset_url }}" alt="">
<h3>{{ block.settings.title }}</h3>
<p>{{ block.settings.description }}</p>
</div>
{% endfor %}
Including a snippet
Pull in a reusable Liquid partial with {% render %}:
{% render 'package-card' with package: pkg, show_badge: true %}
Comments
{%- comment -%}
This text is removed during rendering.
Useful for notes to other authors.
{%- endcomment -%}
Whitespace control
Add a hyphen inside the tag delimiter to strip surrounding whitespace.
{% if customer -%}
Hi!
{%- endif %}
Without the hyphens, Liquid keeps the linebreaks around the tags. Use them to keep your rendered HTML tidy.
Limits to be aware of
Templates can't make HTTP requests, read files, or call eval-style dynamic code. Each section render also has a maximum execution time and output size — extremely heavy templates will be cut off and the section will fail to render. The editor surfaces a budget meter when a section is approaching a limit. In practice, normal section code is nowhere near these limits.
FAQ
Where can I find the full filter list?
The visual editor's autocomplete in the code editor surfaces them as you type. As a starting point, all standard Liquid filters work, plus Storra-specific filters like asset_url, image_url, format_money, and url_safe.
Can I use JavaScript-style arrow functions or async/await?
No — Liquid is a templating language, not JavaScript. Logic in templates is limited to what the tags and filters support. For dynamic behavior, use JavaScript files in assets/ and reference them from your Liquid (see CSS & asset editing).
What does {{ "now" | date: "%Y" }} output?
The current year as a four-digit number — e.g. "2026". "now" is a special string that resolves to the current timestamp; date: formats it. Useful for copyright lines.
Updated recently