Shopify Liquid powers almost every theme on the platform. If you want to change how products display, how collections render, or how your cart behaves, you need to understand Liquid. The good news is that you can learn enough to make meaningful edits without a computer science degree.
The bad news is that one careless edit can break your storefront. A missing tag, a bad loop, or a typo in a filter can take down a page or hide a product. This Shopify Liquid tutorial walks you through the language step by step and shows you how to customize your theme safely.
By the end, you will know how Liquid works, where to edit it, and how to protect your live store while you experiment. Let’s get started.
## What Is Shopify Liquid and Why It Matters
Liquid is an open-source template language created by Shopify. It sits between your theme files and your store data. When a shopper visits a page, Liquid pulls data from your store and fills in the HTML.
Think of Liquid as the bridge. Your theme has static HTML and CSS. Your store has dynamic data like product titles, prices, and images. Liquid connects the two.
Every Shopify theme is built with Liquid. That means when you learn Shopify Liquid, you gain the ability to control nearly any part of your storefront’s appearance and logic.
Liquid is also safe by design. It cannot run arbitrary server code, so you cannot accidentally expose your database or crash the backend. The worst you can do is break a template, which is recoverable.
## The Three Building Blocks of Liquid
Liquid has three core pieces. Once you understand these, the rest is just vocabulary.
| Element | Syntax | Purpose |
|:——–|:——-|:——–|
| Objects | `{{ }}` | Output dynamic content like a product title |
| Tags | `{% %}` | Logic and control flow like loops and conditions |
| Filters | `\|` | Modify output, like formatting a price |
### Objects
Objects output data. You wrap them in double curly braces.
“`liquid
{{ product.title }}
{{ product.price | money }}
{{ shop.name }}
“`
Each object holds specific data. The `product` object holds product details. The `shop` object holds store settings. Shopify documents every object and its properties.
### Tags
Tags handle logic. They use curly braces with percent signs. Tags do not output anything by themselves.
“`liquid
{% if product.available %}
In stock
{% else %}
Sold out
{% endif %}
“`
Notice the closing tags. Every `if` needs an `endif`. Every `for` needs an `endfor`. Forgetting a closing tag is the most common beginner mistake.
### Filters
Filters change how data appears. You add them after a pipe character.
“`liquid
{{ product.title | upcase }}
{{ product.price | money }}
{{ “hello world” | capitalize }}
“`
You can chain filters together. They apply left to right.
“`liquid
{{ product.title | upcase | truncate: 20 }}
“`
## Understanding Theme File Structure
Before you edit anything, know where Liquid lives. A Shopify theme follows a predictable folder structure.
| Folder | What It Holds |
|:——-|:————–|
| `layout` | Main wrapper files like `theme.liquid` |
| `templates` | Page-level templates for products, collections, pages |
| `sections` | Reusable, customizable content blocks |
| `snippets` | Small reusable code chunks |
| `assets` | CSS, JavaScript, images |
| `config` | Theme settings and schema |
| `locales` | Translation files |
Most customization happens in `sections` and `snippets`. Sections are the modern way to build flexible layouts. If you want to go deeper on this, read our guide on how to [build custom Shopify sections] with Liquid and JSON schema.
Snippets help you avoid repeating code. You include them with the `render` tag.
“`liquid
{% render ‘product-card’, product: product %}
“`
## How to Edit Liquid Safely
This is the most important part of any Shopify Liquid code guide. Editing a live theme is risky. Here is how to avoid disaster.
### Always Duplicate Your Theme First
Never edit your live theme directly. Go to Online Store, then Themes, and duplicate the active theme. Edit the copy.
Once you confirm your changes work, publish the copy. This gives you a clean fallback if something breaks.
### Use Git for Version Control
Duplicating works for small edits, but professional teams use version control. Git lets you track every change and roll back instantly. Our walkthrough on [Shopify theme version control with Git] shows the full workflow.
With Git and the Shopify CLI, you can pull your theme locally, edit it in your code editor, and push changes back. This is far safer than the web editor.
### Test in the Theme Editor
The theme editor shows a live preview. Use it to check your changes before publishing. Click through product pages, collections, and the cart.
### Keep a Changelog
Write down what you change and why. When something breaks weeks later, your notes save hours of debugging.
## Your First Liquid Customization
Let’s make a real edit. We will add a custom message to product pages when stock runs low.
Open your product template or section. Find where the product data renders. Add this code.
“`liquid
{% if product.available and product.selected_or_first_available_variant.inventory_quantity < 5 %}
Only {{ product.selected_or_first_available_variant.inventory_quantity }} left in stock
{% endif %}
“`
This checks two things. First, that the product is available. Second, that inventory is below five. Only then does it show the warning.
Note that inventory quantity only works if you track inventory and expose it in the theme. Some themes hide this data for performance reasons.
## Working With Loops
Loops repeat content for each item in a collection. You use the `for` tag.
“`liquid
{% for product in collection.products %}
{{ product.title }}
{{ product.price | money }}
{% endfor %}
“`
This loops through every product in a collection and prints its title and price.
You can limit loops to improve performance.
“`liquid
{% for product in collection.products limit: 4 %}
{{ product.title }}
{% endfor %}
“`
Limiting loops matters for speed. Large loops slow down page rendering. For more on this, see our guide on [Shopify Liquid optimization].
Liquid also gives you loop helpers.
| Helper | What It Does |
|:——-|:————-|
| `forloop.index` | Current iteration number, starting at 1 |
| `forloop.first` | True on the first item |
| `forloop.last` | True on the last item |
| `forloop.length` | Total number of items |
Here is a practical example using `forloop.first`.
“`liquid
{% for image in product.images %}
{% if forloop.first %}
{% endif %}
{% endfor %}
“`
## Conditionals and Logic
Conditionals let you show content based on rules. You already saw `if`. There is also `unless`, `elsif`, and `case`.
“`liquid
{% if customer %}
Welcome back, {{ customer.first_name }}
{% else %}
Please log in
{% endif %}
“`
The `case` tag works well when you compare one value against many options.
“`liquid
{% case product.type %}
{% when ‘Shirt’ %}
This is apparel
{% when ‘Mug’ %}
This is a drinkware item
{% else %}
Standard product
{% endcase %}
“`
Use `case` instead of long chains of `elsif` for cleaner code.
## Variables and Assignments
You can store values in variables. This keeps your code readable.
“`liquid
{% assign sale_price = product.price | times: 0.8 %}
Sale price: {{ sale_price | money }}
“`
The `capture` tag stores blocks of content in a variable.
“`liquid
{% capture discount_message %}
Save {{ product.compare_at_price | minus: product.price | money }}
{% endcapture %}
{{ discount_message }}
“`
Variables only exist within the file where you create them. They do not carry across templates.
## Working With Metafields
Metafields store extra data that standard fields do not cover. Think care instructions, ingredient lists, or custom specs.
You access them through the `metafields` object.
“`liquid
{{ product.metafields.custom.care_instructions }}
“`
Metafields unlock powerful customization. You can build rich product pages without hardcoding content. Our complete [Shopify metafields guide] covers setup, metaobjects, and real use cases.
Always check that a metafield exists before you output it.
“`liquid
{% if product.metafields.custom.care_instructions %}
{% endif %}
“`
## Common Liquid Filters You Will Use Daily
Filters do a lot of heavy lifting. Here are the ones you will reach for most often.
| Filter | Example | Result |
|:——-|:——–|:——-|
| `money` | `{{ 1999 \| money }}` | $19.99 |
| `image_url` | `{{ img \| image_url: width: 400 }}` | Sized image URL |
| `date` | `{{ date \| date: “%B %d, %Y” }}` | January 15, 2025 |
| `truncate` | `{{ text \| truncate: 50 }}` | Shortened text |
| `default` | `{{ title \| default: “No title” }}` | Fallback value |
| `escape` | `{{ input \| escape }}` | Safe HTML output |
The `image_url` filter matters most for performance. Always request the right size instead of loading full-resolution images.
“`liquid
“`
This loads responsive, lazy-loaded images. That improves Core Web Vitals and speeds up your store.
## Building Custom Sections With Schema
Sections become truly powerful when you add a schema. The schema turns hardcoded values into merchant-editable settings.
“`liquid
{% schema %}
{
“name”: “Featured Banner”,
“settings”: [
{
“type”: “text”,
“id”: “heading”,
“label”: “Heading”
},
{
“type”: “image_picker”,
“id”: “banner_image”,
“label”: “Banner image”
}
]
}
{% endschema %}
“`
Then reference the settings in your Liquid.
“`liquid
{{ section.settings.heading }}
{% if section.settings.banner_image %}
{% endif %}
“`
This lets merchants edit content from the theme editor without touching code. It is the foundation of flexible theme design.
## Common Mistakes and How to Avoid Them
Beginners hit the same walls repeatedly. Here is how to dodge them.
### Forgetting Closing Tags
Every block tag needs a close. Miss one and the whole template breaks. Use a code editor that highlights matching tags.
### Outputting Raw HTML Unsafely
User input can contain malicious code. Always use the `escape` filter on any dynamic text that could hold HTML.
### Ignoring Nil Values
If an object does not exist, Liquid outputs nothing or throws odd results. Guard your output with `if` checks or the `default` filter.
### Overloading Loops
Looping through thousands of products slows your store. Always add a `limit`. If you need heavy data processing, consider moving it outside Liquid entirely.
### Editing the Live Theme
We said it before, but it bears repeating. Edit a duplicate, test, then publish.
## When Liquid Is Not Enough
Liquid handles presentation well. But it has limits. It runs at render time and cannot perform complex operations or external calls.
If you need advanced interactivity, you may need JavaScript or a custom app. For heavy backend logic, [building a Shopify app] gives you full control over data and processing.
Some teams move to a headless setup for maximum flexibility. Our comparison of [Shopify Hydrogen vs Liquid] helps you decide when going headless makes sense.
For checkout customization specifically, Liquid no longer works on the checkout page. You need [Shopify checkout UI extensions] instead. These replace the old checkout.liquid approach.
## Fetching Data Beyond the Theme
Liquid pulls data that Shopify exposes to the theme. For everything else, you use the APIs. The [Shopify GraphQL API] lets you query store data efficiently from apps and integrations.
If your project involves syncing data with external systems, explore our work on [scalable Shopify integration patterns] and [data mapping strategies]. These matter when your store grows beyond a basic catalog.
For stores handling heavy traffic, performance planning extends beyond the theme. Read how we approach [scaling Shopify systems during flash sales] to prepare for peak demand.
## A Safe Customization Workflow
Here is a repeatable process for every Liquid edit.
1. Duplicate your live theme or pull it locally with Git.
2. Make one focused change at a time.
3. Preview in the theme editor.
4. Test on mobile and desktop.
5. Check related pages that might be affected.
6. Publish or push only after confirming the fix.
7. Record the change in your changelog.
Small, tested changes beat big risky edits every time. This discipline keeps your store stable as you learn.
## Practicing Without Risk
The best way to learn Shopify Liquid is to practice on a development store. Shopify partners get free development stores. Use one as your sandbox.
Install the Dawn theme. It is Shopify’s reference theme and follows best practices. Study how its sections and snippets fit together.
Change small things. Break things on purpose. See what the errors look like. That builds real understanding faster than reading alone.
When you feel confident, move to real projects. If your store is business-critical and you need expert help, our team at Kolachi Tech handles complex Shopify theme and app work daily.
## Final Thoughts
Liquid is approachable once you break it into its three pieces: objects, tags, and filters. From there, everything builds on the same patterns. Loops, conditionals, and variables give you real control over your storefront.
The key to safe customization is discipline. Always work on a copy. Test every change. Keep notes. Use version control as your edits grow.
Start small. Add a low-stock warning. Build a simple section. Each win builds confidence. Before long, you will shape your theme exactly how you want it, without ever breaking your live store.
## Frequently Asked Questions
### What is Shopify Liquid used for?
Liquid is Shopify’s template language. It connects your theme’s HTML with your store’s data, so pages display dynamic content like product titles, prices, and images.
### Can I break my store by editing Liquid?
Yes, a single syntax error can break a page. Always edit a duplicate theme, test your changes, then publish. Git version control adds an extra safety net.
### Where do I edit Liquid code in Shopify?
Go to Online Store, then Themes, click the three dots, and select Edit code. Most edits happen in the sections and snippets folders.
### Do I need to know coding to learn Shopify Liquid?
Basic HTML and CSS knowledge helps a lot. Liquid itself is simple to learn, built around objects, tags, and filters that follow consistent patterns.
### What is the difference between Liquid and the Shopify API?
Liquid renders theme content at page load. The API lets apps and integrations query or change store data programmatically, handling logic Liquid cannot perform.
### Why can’t I use Liquid on the checkout page anymore?
Shopify replaced checkout.liquid with checkout UI extensions for security and consistency. You now customize checkout using these extensions instead of Liquid templates.
