What Is Liquid and How Does It Work?
Liquid is a template language — a system that combines static HTML with dynamic data to generate web pages. When a customer visits your Shopify store, Liquid templates are processed on Shopify's servers, the dynamic data (product names, prices, images, cart contents) is inserted into the HTML, and the resulting page is delivered to the customer's browser.
Unlike general-purpose programming languages like JavaScript or Python, Liquid is intentionally limited in scope. It cannot access the filesystem, make network requests, or execute arbitrary code. This makes it secure — even if a theme developer makes a mistake, Liquid's constraints prevent it from causing security vulnerabilities or crashing the server. Shopify chose this design deliberately to ensure that all themes on their platform are safe and performant.
Liquid consists of three fundamental components that every Shopify developer needs to understand: objects (which output data), tags (which control logic), and filters (which modify output). With just these three building blocks, you can create any storefront layout, display any product data, implement conditional logic, and build complex theme functionality.
You do not need to learn Liquid to run a successful Shopify store. Shopify's visual theme editor handles most customization needs. However, understanding Liquid unlocks deeper customization: conditional product badges, custom promotional banners, personalized content based on customer tags, and advanced layout modifications that go beyond what the theme editor offers.
Liquid Objects: Accessing Store Data
Objects are the data layer of Liquid. They represent store data — products, collections, cart items, customer information — and are accessed using double curly braces: {{ object.property }}. When Shopify processes a template, it replaces objects with their actual values.
The Most Important Liquid Objects
product — Represents a single product. Available on product pages.
{{ product.title }}— The product name{{ product.price | money }}— The current price, formatted as currency{{ product.description }}— The product description HTML{{ product.featured_image | image_url: width: 600 }}— URL for the featured image at 600px width{{ product.variants }}— Array of product variants (sizes, colors){{ product.available }}— Whether the product is in stock (true/false){{ product.compare_at_price | money }}— The original/compare-at price for sale items{{ product.tags }}— Array of product tags
collection — Represents a group of products. Available on collection pages.
{{ collection.title }}— The collection name{{ collection.products }}— Array of products in the collection{{ collection.products_count }}— Number of products{{ collection.description }}— Collection description HTML
cart — Represents the current shopping cart. Available globally.
{{ cart.total_price | money }}— Cart total formatted as currency{{ cart.item_count }}— Number of items in cart{{ cart.items }}— Array of line items
customer — Represents the logged-in customer. Available when authenticated.
{{ customer.first_name }}— First name{{ customer.email }}— Email address{{ customer.orders_count }}— Total number of orders{{ customer.total_spent | money }}— Lifetime spend{{ customer.tags }}— Customer tags array
shop — Represents the entire store. Available globally.
{{ shop.name }}— Store name{{ shop.url }}— Store URL{{ shop.currency }}— Store currency code
Liquid Tags: Logic and Control Flow
Tags control the logic of templates. They are enclosed in curly-brace-percent delimiters: {% %}. Tags do not produce visible output — they control what content is rendered and how.
Conditional Tags
The if, elsif, else, and unless tags control conditional rendering:
Show a "Sale" badge only when a product has a compare-at price: {% if product.compare_at_price > product.price %} <span class="sale-badge">Sale</span> {% endif %}
Show different messages based on cart value: {% if cart.total_price >= 7500 %} You qualify for free shipping! {% elsif cart.total_price >= 5000 %} Add {{ 7500 | minus: cart.total_price | money }} more for free shipping {% else %} Free shipping on orders over $75 {% endif %} (Note: Liquid prices are in cents, so 7500 = $75.00)
Iteration Tags
The for loop iterates over arrays:
Loop through products in a collection: {% for product in collection.products %} <h2>{{ product.title }}</h2> <p>{{ product.price | money }}</p> {% endfor %}
The limit and offset parameters control pagination: {% for product in collection.products limit: 4 %} shows only the first 4 products.
Variable Tags
assign creates a new variable: {% assign sale_price = product.price | times: 0.8 %}
capture captures a block of content into a variable: {% capture greeting %}Hello, {{ customer.first_name }}!{% endcapture %}
Theme Tags
section renders a reusable theme section: {% section 'header' %}
render includes a snippet (partial template): {% render 'product-card', product: product %}
layout specifies which layout file to use: {% layout 'alternate' %}
Liquid Filters: Transforming Output
Filters modify the output of objects and literals. They are applied using the pipe character | and can be chained for multiple transformations.
Money Filters
{{ product.price | money }}— Formats as currency ($49.99){{ product.price | money_with_currency }}— Includes currency code ($49.99 USD){{ product.price | money_without_trailing_zeros }}— Removes .00 ($49 instead of $49.00)
String Filters
{{ product.title | upcase }}— UPPERCASE{{ product.title | downcase }}— lowercase{{ product.title | truncate: 50 }}— Truncates to 50 characters{{ product.title | handleize }}— Converts to URL-safe handle (my-product){{ product.description | strip_html }}— Removes HTML tags{{ 'cart' | pluralize: cart.item_count }}— Pluralizes based on count
Image Filters
{{ product.featured_image | image_url: width: 400 }}— Generates responsive image URL{{ product.featured_image | image_tag: loading: 'lazy' }}— Generates complete img tag with lazy loading
Math Filters
{{ product.price | times: 0.9 }}— Multiply (10% discount){{ product.price | minus: 500 }}— Subtract ($5.00 off){{ product.price | divided_by: 4 }}— Divide (installment price)
Shopify Theme File Structure
Every Shopify theme follows a standard directory structure. Understanding this structure is essential for making Liquid modifications.
| Directory | Purpose | Key Files |
|---|---|---|
| layout/ | Base HTML wrapper for all pages | theme.liquid (main layout), password.liquid |
| templates/ | Page-type templates | index.json, product.json, collection.json, cart.json, page.json |
| sections/ | Reusable content blocks | header.liquid, footer.liquid, product-template.liquid, hero.liquid |
| snippets/ | Small reusable code fragments | product-card.liquid, price.liquid, social-icons.liquid |
| assets/ | Static files (CSS, JS, images) | theme.css, theme.js, logo.svg |
| config/ | Theme settings | settings_schema.json, settings_data.json |
| locales/ | Translation strings | en.default.json, fr.json, de.json |
Online Store 2.0 and Sections
Online Store 2.0 (OS 2.0) is Shopify's modern theme architecture, introduced in 2021. It replaced the rigid template system with a flexible, section-based approach that gives merchants much more control over page layout without touching code.
In OS 2.0, templates are JSON files that define which sections appear on a page and in what order. Sections are self-contained Liquid files that include their own HTML, CSS, JavaScript, and schema (configuration options). Merchants can add, remove, reorder, and configure sections through the visual theme editor.
For Liquid developers, OS 2.0 means building sections with rich {% schema %} blocks that expose settings to the theme editor. A well-built section lets merchants customize colors, text, layout, and behavior without editing code — while the Liquid template underneath handles the dynamic rendering.
Practical Liquid Examples
Display a Sale Badge
Show a percentage-off badge when a product is on sale:
{% if product.compare_at_price > product.price %} {% assign discount = product.compare_at_price | minus: product.price | times: 100.0 | divided_by: product.compare_at_price | round %} <span class="sale-badge">-{{ discount }}%</span> {% endif %}
Free Shipping Progress Message
Show how much more the customer needs to spend for free shipping:
{% assign threshold = 7500 %} {% if cart.total_price >= threshold %} <p>You have earned free shipping!</p> {% else %} {% assign remaining = threshold | minus: cart.total_price %} <p>Add {{ remaining | money }} more for free shipping</p> {% endif %}
For a more polished implementation, the EA Free Shipping Bar provides an animated progress bar with geolocation and multi-currency support — no Liquid coding required.
Personalized Welcome Message
Greet logged-in customers by name:
{% if customer %} <p>Welcome back, {{ customer.first_name }}!</p> {% else %} <p>Welcome! <a href="/account/login">Sign in</a> for a personalized experience.</p> {% endif %}
Conditional Content Based on Product Tags
Show special messaging for products tagged with specific labels:
{% if product.tags contains 'new-arrival' %} <span class="badge new">New Arrival</span> {% endif %} {% if product.tags contains 'bestseller' %} <span class="badge best">Bestseller</span> {% endif %} {% if product.tags contains 'limited-edition' %} <span class="badge limited">Limited Edition</span> {% endif %}
Liquid Performance Best Practices
Minimize Liquid Loops
Every for loop adds server processing time. Avoid nesting loops (a loop inside a loop) whenever possible. Use limit to reduce iterations when you only need a subset of items. For product-heavy pages, lazy loading and pagination are more performant than rendering all products in a single loop.
Use render Instead of include
The {% render %} tag is faster than the deprecated {% include %} tag because it creates an isolated scope. It also prevents variable leaking between snippets, making templates more predictable and maintainable.
Optimize Image Loading
Always use the image_url filter with a specific width to serve appropriately sized images: {{ product.featured_image | image_url: width: 400 }}. For additional image optimization and performance improvements, the EA Page Speed Booster handles lazy loading, compression, and script deferral automatically.
Cache Expensive Operations
If you need the same calculated value multiple times in a template, assign it to a variable once rather than recalculating: {% assign sale_percentage = product.compare_at_price | minus: product.price | times: 100 | divided_by: product.compare_at_price | round %} — then reference {{ sale_percentage }} wherever needed.
How to Customize Your Shopify Theme with Liquid
Getting Started Safely
- Always work on a duplicate theme — In Online Store > Themes, click "Duplicate" on your live theme. Make all changes on the copy, preview, and only publish when satisfied.
- Use the code editor — Go to Online Store > Themes > Edit code to access Liquid files directly in the browser. No development environment needed for small changes.
- Use Shopify CLI for larger changes — For significant customization, install Shopify CLI to work locally with your preferred code editor, hot reloading, and version control.
- Test on a development store — Sign up for a free Shopify Partners account to get unlimited development stores for testing.
Common Customizations
- Add custom product badges — Edit the product card snippet to show sale, new, or bestseller badges based on product tags.
- Custom promotional banners — Create a new section with settings for banner text, link, and background color. Add it to any page through the theme editor.
- Conditional free shipping messaging — Add cart-total-based messaging to the cart template showing progress toward free shipping. Or install the EA Free Shipping Bar for a polished solution without coding.
- Customer-specific content — Use
{% if customer.tags contains 'vip' %}to show exclusive content or pricing to VIP customers. - Product page enhancements — Add size guides, ingredient lists, or care instructions as metafield-driven sections on product pages.
When to Use Apps Instead of Custom Liquid
Not every customization needs custom Liquid code. Shopify apps handle common functionality with polished UI, ongoing maintenance, and zero code required. For email capture, the EA Email Popup & Spin Wheel provides sophisticated popup functionality. For conversion optimization, tools like EA Sticky Add to Cart and EA Countdown Timer add proven conversion elements without theme modifications. For upselling and cross-selling, EA Upsell & Cross-Sell manages recommendation logic automatically. Apps are preferable when functionality requires ongoing updates, complex logic, or integrations with external services.
Frequently Asked Questions
What is Shopify Liquid?
Shopify Liquid is an open-source template language created by Shopify and written in Ruby. It is the backbone of every Shopify storefront, controlling how dynamic store data — products, collections, customer information, and cart contents — is rendered as HTML. Liquid uses objects (data), tags (logic), and filters (output modification) to generate pages.
Do I need to know Liquid to run a Shopify store?
No. Shopify's theme editor and Online Store 2.0 allow extensive customization without code. You can change layouts, add sections, modify colors and fonts, and configure apps visually. Learning basic Liquid unlocks deeper customization, but it is not required for running a successful store.
What is the difference between Liquid objects, tags, and filters?
Objects ({{ }}) output dynamic content like product titles and prices. Tags ({% %}) control logic and flow — conditionals, loops, and variable assignments. Filters (|) modify output — formatting currency, truncating text, or transforming images. Together, these three components make up the entire Liquid language.
What are the most commonly used Liquid objects?
The most commonly used Liquid objects are: product (title, price, images, variants), collection (products, title), cart (items, total_price, item_count), customer (name, email, orders), and shop (name, url, currency). These objects are available in their respective template contexts.
Where can I learn more about Shopify Liquid?
The best resources are: Shopify's official Liquid documentation at shopify.dev, the Dawn theme source code on GitHub, Shopify's free "Liquid Essentials" course on Shopify Learn, and community forums. For hands-on practice, use a free Shopify Partners development store to experiment with Liquid.
Skip the Code — Get Results with Free Apps
The EasyApps Ecommerce suite gives you conversion optimization, email capture, upselling, and speed optimization — no Liquid coding required. 10 free apps that work with any Shopify theme out of the box.
Browse All Free Apps