An Overview of Liquid: Shopify's Templating Language

Shopify liquid

If you are new to the Shopify platform and read through our content, you might be wondering what all the references to Liquid actually refer to. In this article, we'll explain all you need to know about Liquid, how it fits into Shopify theme building, and the core concepts that will enable you to start building powerful and immersive ecommerce templates. Let's begin with a little history.

Liquid was developed by Shopify co-founder and CEO Tobias Lütke and is now available as an open source project on GitHub. Today, it's used in many different software projects, from content management systems to static site generators—and of course, Shopify.

Template Icon

Liquid: language or engine?

Some refer to Liquid as a template language, while others may call it a template engine. It doesn't really matter which label you apply—in many ways both are right. Personally, I like to call it a template language. It has a syntax (like traditional programming languages), has concepts such as output, logic, and loops, and it interacts with variables (data), just as you would with a web-centric language such as PHP.

However, that's really where the similarities end. There's a lot you can't do with Liquid—by design. For example, it has no concept of "state," it doesn't let you get deep under the covers of the platform, and can occasionally seem counter intuitive for seasoned coders. However, it has been very well thought out and what might at first seem like a limitation is usually intended, and for good reason.

Explore Shopify Liquid Code Examples

Visit our searchable library of Liquid code examples based around theme components. Learn how various Liquid objects, properties, and filters work together as part of components within a theme. Add them directly into themes to build and customize themes faster and more reliably.

Visit Shopify Liquid Code Examples

Liquid's function

Liquid, like any template language, creates a bridge between an HTML file and a data store—in our context, the data is of course a Shopify store. It does this by allowing us to access variables from within a template, or Liquid file, with a simple to use and readable syntax.

In Shopify, each Liquid file allows us to access certain variables without having to do any heavy lifting. For example, the product.liquid template allows us access to all the details relating to the currently viewed product. Liquid, in turn, allows us to output this data without having to know anything about the actual product itself. These variables are known as template variables. You can also use Liquid to retrieve data that isn't made available to us. For example, you can ask Shopify to populate a variable you create with all the products in a particular collection.

Once we know the names of the variables we have access to or create, we can use Liquid constructs such as "output" and "loops" to display the data in our Liquid files.

The Shopify platform understands what data to retrieve, and how to display it depending on the Liquid code you have in your theme. It might be a simple case of displaying the name of a product or something slightly more complex, such as showcasing a series of product images.

The great benefit of a template language such as Liquid is that you, as the designer, don't need to know anything about the store data itself. As such, your themes are 100 percent agnostic and can be applied to multiple stores without any knowledge of the stores content.

You might also like: The 8 Best Free Shopify Resources and Tools for Front-End Developers.

Liquid's file extension and delimiters

Liquid files have the extension of .liquid. A liquid file is a mix of standard HTML code and Liquid constructs. It's an easy to read syntax, and is easy to distinguish from HTML when working with a Liquid file. This is made even easier thanks to the use of two sets of delimiters.

The double curly brace delimiters {{ }} denote output, and the curly brace percentage delimiters {% %} denote logic. You'll become very familiar with these as every Liquid construct begins with one or the other.

Another way of thinking of delimiters is as "placeholders." A placeholder can be viewed as a piece of code that will ultimately be replaced by data when the compiled theme is sent to the browser. This data is determined entirely by the theme designer as a result of the Liquid code in the Liquid file. As such, Liquid themes, much like templates that inter splice PHP and HTML, serve as representations of what will be rendered.


Let's examine the syntax for "output." As the name suggests, output in Liquid will literally output a piece of data from our store onto a page.

Here's a quick example of an output placeholder that you will typically find in the product.liquid file:

<h2>{{ product.title }}</h2>

When rendered, this would output the name of the currently viewed product in place of the {{ }}, for example:

<h2>American Diner Mug</h2>

Output, unless manipulated with a filter (which we will look at shortly) is simply a case of replacing the entire placeholder with a text string from your store.

Objects and properties

This example also introduces us to the Liquid dot syntax. This is common in many template and server side languages. Taking our example we can break it up into two parts.

The first element preceding the . is the object—in this case, it is the shop object. This is a variable that represents all the data relating to the shop that we have defined in the Shopify admin. These data items include:

  • shop.address
  • shop.address.country_upper
  • shop.address.province
  • shop.address.province_code
  • shop.address.street
  • shop.address.summary
  • shop.collections_count
  • shop.currency
  • shop.description
  • shop.domain
  • shop.enabled_currencies
  • shop.enabled_payment_types
  • shop.metafields
  • shop.money_format
  • shop.money_with_currency_format
  • shop.password_message
  • shop.permanent_domain
  • shop.policies
  • shop.privacy_policy
  • shop.products_count
  • shop.published_locales
  • shop.refund_policy
  • shop.shipping_policy
  • shop.terms_of_service
  • shop.secure_url
  • shop.taxes_included
  • shop.types
  • shop.url
  • shop.vendors

The items following the . represent properties of the shop object. A property could be as simple as the name of the store (as per our example above) or it could be a list of items, such as the kinds of payment types enabled in the store.

You might also like: The Essential List of Resources for Shopify Theme Development.

Collection properties

You will notice from the list above that a number of the properties are plural, e.g:

  • shop.enabled_payment_types
  • shop.metafields
  • shop.types

These properties represent Liquid collections. Instead of returning a string of data such as the name of the shop they will return an array of data — in other words, a list of items we can access via a Liquid loop.

When first using Shopify and Liquid, it's easy to get confused by collections—I certainly did. I will therefore refer to "product collections" and "Liquid collections." The former being a logical grouping of products defined in the Shopify Admin, and the latter being a list of items we can access in Liquid code.

Finally, it's worth saying that each one of the list items in our Liquid collection can also have properties. A good example of this is product.images. This represents a list of all the images that have been added to a particular product.

Each of the images in the list has multiple properties associated with it:

  • image.alt
  • image.aspect_ratio
  • image.attached_to_variant?
  • image.height
  • image.media_type
  • image.position
  • image.preview_image
  • image.product_id
  • image.src
  • image.variants
  • image.width

In order to access these properties, we have to use a Liquid loop.

Liquid loops

Loops are used extensively in Shopify themes, and are thankfully very easy to understand. If you have done any form of basic programming, the concept of loops will likely be very familiar to you.

Using a loop, often known as a for loop, allows us to output the same piece of code a known number of times in our Liquid file. As mentioned above, a typical example would be to output all the images associated with a product.

Let's have a look at an example using the product.images Liquid collection I discussed earlier.

Our aim with this loop is to output all of the images for a particular product. Here's a very simplistic loop that will output each image inline:

{% for image in product.images %}
<img src="{{ image | img_url: '300x300' }}">
{% endfor %}

Let's break it down into steps to fully understand it.

Template Icon

Step 1

{% for image in product.images %}

The first line introduces us to the second style of delimiter, the curly brace percentage syntax {% %}. Here, we are using a Liquid for loop. Loops work with Liquid collections, and allow us to iterate over each item in our list in turn. If the product we are currently viewing had six images associated with it, our for loop would loop six times, if it had 10 then it would loop 10 times, and so on. Only once every list item has been looked at (or unless we instruct it otherwise), will the next part of the page be considered.

It's worth noting that unless we specifically ask how big our loop will be, we don't know how many loops will occur—only that Liquid will go through every item in our list, in turn. The loop will finish after the last iteration, and it's at this point that the page will carry on with its processing.

In order to access the properties of each list item, we designate a variable to represent the current item in the loop. In our example above it is image. While this is an obvious choice, and will help other designers understand your logic in the future, it can literally be anything. For example, we could use alltheimagesintheworld, in which case it would look as follows:

{% for alltheimagesintheworld in product.images %}

This is of course a silly example to make a point—image makes much more sense, but I just wanted to emphasize the fact that this variable has no relation to the Liquid collection.

Step 2

<img src="{{ image | img_url: '300x300' }}" />

The second line of our code example consists of part HTML and part Liquid. You'll also notice that the src attribute is populated with a Liquid output tag.

This introduces us to the concept of filters which are denoted by the | (pipe) character—we'll look at these in more detail shortly. In our example, the filter is taking the image variable (the current item in our loop) and is specifying the dimensions, in pixels, the image should be displayed. 

We'll look at filters, denoted by the | character, next, but suffice to say that the parameters we define will populate the src attribute with a fully qualified URL to the current image in our list. The filter does all the work of creating the src attribute for us.

Step 3

{% endfor %}

The final line of our example is our closing endfor statement. This tells the template to carry on after all the loops have been executed.

If we had three images in our product.images object, the final output would look something like this:

<img src="//" alt="plant-in-clay-pot" />
<img src="//" alt="plant-in-green-pot" />
<img src="//" alt="plant-in-white-pot" />

Loops are really useful and something you will encounter daily in your theme development. Outputting images and product variants are two commonly found examples.

You might also like: How to Use Shopify Theme Settings to Create Mobile-Specific Logos.

Liquid filters

Another very powerful feature of Liquid are output filters, which I used in the code example above. Filters serve three main purposes:

  • They manipulate output data in some way
  • They allow our themes to be agnostic
  • They save theme designers time by reducing the amount of code we need to write

Filters are always used in conjunction with a Liquid output. Let's have a look at some filters starting with the date filter.

When outputting a blog post, you'll likely want to let the reader know when it was published:

<p class="date-time">{{ article.published_at | date: '%d %B %Y' }}</p>

As before you'll notice the | character (often referred to as a pipe) in the middle of the output tag. On the left side of the pipe, we have the article object with its associated published_at property, and on the right we have the date filter with an argument to denote the date format—in this case '%d %B %Y'.

Without the filter, Shopify would simply output the date the blog article was published at in the format it is stored in the database—which may not be humanly readable. However, by adding in the | and including the date filter, we can manipulate the format so it outputs in a format we want.

Put simply, filters allow us to take a piece of data from our store and change it. What we start with on the left hand side gets "piped" through our filter and emerges on the right hand sized changed. It's this final manipulated data that is then output on the front end of the theme.

Here's another example:

{{ 'style.css' | asset_url | stylesheet_tag }}

Here we are using two filters with the ultimate aim of creating a fully formed style element in a layout file.

We start on the left with the name of the our CSS file, which resides in the assets folder. Next we apply our first filter—in this case the asset_url filter. This is an incredibly useful filter and one you'll use a lot. 

I mentioned before how Shopify themes, thanks to Liquid, are agnostic. They don't need to have any knowledge of the store they are working against and the same theme can be applied to multiple stores. However, this can cause issues when trying to reference assets as we need a way of knowing where a certain asset (image, JS file, CSS file) is on the network.

Thankfully the asset_url comes to our rescue. By using this filter, Shopify will return the fully qualified path to the assets folder for the theme and append the name of our asset at the end. Just remember it won't actually check that the file exists—it's up to us to ensure that the first part of the tag, in our case style.css is in the assets folder.

Here's how that might look when output:


The final filter in the chain, stylesheet_tag, takes the URL and wraps it in a style element which is then output in our layout file. Here's the final result:

<link href= "//" rel="stylesheet" type="text/css" media="all" />

There are many really useful filters, here are just a few you'll find yourself using:

  • asset_url
  • stylesheet_tag
  • script_tag
  • date
  • pluralize
  • replace
  • handle
  • money
  • money_with_currency
  • img_url
  • link_to

Liquid logic

The final aspect of Liquid we need to look at is logic. Here's an example:

{% if product.available %}
<h2>Price: £99.99</h2>
{% else %}
<h2 class="sold-out">Sorry - sold out</h2>
{% endif %}

In this snippet, we are controlling the output to our liquid file using a simple if, else, endif statement. In many ways, if statements are like questions. Depending on the answer to the question a different piece of markup will be output—or in some cases no markup at all.

In the above example, if the answer to our if statement question is true (product.available returns true or false), we render the words "This product is available." If it's false, our Liquid file carries on and outputs the text following our {% else %} clause—in this case "Sorry, this product is sold out."

Another way of looking at logic is that it allows us to control the flow of a page and ultimately make decisions on which data is displayed. It's worth noting that unlike output tags, the inclusion of logic tags in your Liquid files does not result in anything being directly rendered—rather they allow us to control exactly what is rendered.

You will find yourself using if statements a lot in Shopify theme development. Here's another example:

{% if cart.item_count > 0 %}
<p>You have {{ cart.item_count }} item(s) in your cart</p>
{% else %}
<p>There's nothing in your cart :( Why not have a <a href= "/products"> look at our product range</a></p>
{% endif %}

This snippet demonstrates how you can either display the number of items in a visitor’s cart or output a link to your products.


You'll notice in this example we are using the greater than > operator. As the cart.item_count variable returns the number of items in the current users cart, we can check to see if it is greater than zero, i.e. it has items in it.

If this returns true we can output the message with the current item count, if not we can output:

<p>There's nothing in your cart :( Why not have a <a href= "/products">look at our product range</a></p> instead.

We could actually refactor our example with a filter. By using the pluralize filter we can output "item" or "items" depending on the number of items in the cart. The bonus here is that we don't have to know the count in order for Shopify to output the right designation:

{% if cart.item_count > 0 %}
<p>You have {{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }} in your cart</p>
{% else %}
<p>There's nothing in your cart :( Why not have a <a href= "/products">look at our product range</a></p>
{% endif %}

You'll notice that the refactored example now includes the pluralize filter which takes two parameters. The first is the singular word and the second the plural.

While we have used the > operator in the above example, there are a wide range of comparison operators in Liquid including:

  • == equal to
  • != not equal to
  • > greater than
  • < less than
  • >= bigger or equal
  • <= less or equal
  • or this or that
  • and must be this and that
  • contains includes the substring if used on a string, or element if used on an array

By default, even if your Liquid code doesn’t have output, Liquid in a template will still render an empty line in the final HTML. Whitespace control in Liquid enables you to remove this. By using a hyphen in your tag syntax, {{- , -}} , {%- , and -%}, you can strip whitespace from the left or right side of a rendered tag.

Liquid cheat sheet

If you are anything like me, you'll have a hard time committing all these Liquid filters, operators, and structures to memory. Thankfully, the Shopify Liquid Cheat Sheet is available to search all the Liquid objects, tags, and filters, view simple examples, and visit the reference documentation. It's an indispensable resource, which I strongly encourage you to bookmark and become familiar with.

Liquid code examples

Very often we learn through example, so seeing how to implement popular theme components is a great way to learn about how Shopify themes work. The Shopify Liquid Code Examples is a library of theme components that help to inform how various Liquid objects, properties, and filters work together as part of elements within a store.


We've covered a lot of ground in this article, but hopefully it has given you a solid introduction to Liquid. Here's a reminder of what we covered:

  • Liquid is a template language that allows us to display data in a template
  • Liquid has constructs such as output, logic, loops and deals with variables
  • Liquid files are a mixture of HTML and Liquid code, and have the .liquid file extension
  • Liquid files used in a Shopify theme are agnostic and have no concept of the store they are currently being used in
  • The two types of delimiters used in Liquid
  • How to output data from a store in a Liquid file
  • How to manipulate data with filters
  • How to loop over a Liquid collection to output multiple items
  • The use of logic in a Liquid file
  • The different types of operators used for comparison
  • How to control whitespace in Liquid

Want to learn more about building themes for Shopify or your clients? You can learn more about Liquid concepts and how to use it in your own theme development in the Shopify docs


Grow your business with the Shopify Partner Program

Learn more