Clicks & Carts

Shopify Liquid basics: the template language explained

Liquid is small, and you can learn the useful 80% in an afternoon. Here is that 80%, plus the two mistakes that make stores slow.

9 min read · Themes & storefront ·

Liquid is the template language Shopify themes are written in. It's deliberately small — it renders data, it doesn't run business logic — and you can learn the useful part of it in an afternoon. Here's that part, plus the two mistakes that make stores slow.

Three kinds of syntax

Objects output a value:

`` {{ product.title }} ``

Tags control logic and flow, and produce no output themselves:

`` {% if product.available %} In stock {% endif %} ``

Filters transform a value, chained left to right:

`` {{ product.price | money }} {{ product.title | upcase | truncate: 40 }} ``

That's the whole language. Everything else is knowing which objects exist.

The objects you'll use daily

  • product, collection, cart, customer, shop — the obvious ones, available on the templates where they make sense.
  • section and block — the current section and its blocks, plus their settings. The core of sections and blocks.
  • settings — global theme settings from the settings schema.
  • request — information about the current request, including the page type and the locale.
  • routes — never hard-code URLs like /cart; use routes.cart_url so the theme works in every locale and market.
  • content_for_header and content_for_layout — Shopify's injection points in theme.liquid. Removing them breaks the store.

Control flow

``` {% if collection.products_count > 0 %} … {% elsif collection.description != blank %} … {% else %} … {% endif %}

{% for product in collection.products limit: 12 %} {{ product.title }} {% endfor %}

{% case product.type %} {% when 'Chair' %} … {% else %} … {% endcase %} ```

{% assign %} creates a variable; {% capture %} captures a block of output into one. Use blank rather than empty when testing whether a string has anything meaningful in it — blank also catches whitespace.

Filters worth memorising

FilterDoes
moneyFormats a price in the store's currency and format. Never format prices by hand.
image_url / image_tagGenerates correctly sized, responsive images. Central to performance.
tPulls a string from the locale files. Every user-facing string should use it.
defaultFalls back when a value is blank.
escapeEscapes user-supplied content. Use it on anything a customer wrote.
handleizeTurns text into a URL-safe handle.
dateFormats dates.

Snippets and rendering

Repeated markup goes in snippets/ and is included with render:

`` {% render 'product-card', product: product, show_vendor: true %} ``

render gives the snippet its own isolated scope — it only sees what you pass it. That isolation is the point: it makes snippets predictable and, incidentally, faster than the older include tag, which you should not use in new code.

The two performance traps

Nested loops. Iterating every variant of every product in a collection is the classic way to make a page slow. On a 2,000-product collection it's the difference between a page that renders in 200ms and one that takes several seconds — before a single byte reaches the browser. Always bound loops with limit, and if you find yourself looping inside a loop, stop and reconsider the data model.

Repeated expensive lookups. Fetching the same collection or metafield inside a loop re-does the work each iteration. Assign it once outside the loop.

Both show up as slow server response time, which no amount of front-end optimisation fixes. The speed audit covers how to spot it.

The filters worth memorising, with the traps in each, are in the Liquid filters reference.

What Liquid deliberately cannot do

Liquid has no way to call an external API, no database access and no arbitrary computation. That's a design decision, not a limitation to work around. When you need those things, the answer is a custom app or an integration that puts the data somewhere Liquid can read it — usually a metafield.

Trying to fake server-side logic with JavaScript in the theme is how stores end up slow, fragile and hard to debug.

Liquid is small on purpose. Most Liquid problems are actually data-model problems wearing a costume — if the template is fighting you, look at how the data is stored.

Is this the problem you’re looking at?

Send me the link to your store and a line about what is going wrong. You get a straight answer within one business day — no pitch, no obligation.

mario@clicksandcarts.co

Or see what I do around Shopify: services, work beyond the theme, selected work.

Keep reading

← All articles