Liquid is the templating language that powers every Shopify Online Store theme. Whether you are building a theme from scratch, customizing an existing one, or debugging a client's storefront, Liquid fluency is essential. Unlike general-purpose programming languages, Liquid is intentionally sandboxed -- it cannot execute arbitrary code, access the file system, or make network requests. This safety model makes it reliable for multi-tenant hosting but also means you need to think differently about solving problems.
This tutorial progresses from fundamentals to production-grade patterns. If you have programmed in any language before, you will be productive in Liquid within an afternoon.
Liquid uses two types of delimiters:
- Output tags render a value to the page. Example:
product.title outputs the product name.
- Logic tags control flow without producing output. Example:
if product.available starts a conditional block.
Shopify exposes a rich set of global objects. The most commonly used are:
product -- The current product with properties like title, description, price, variants, images, tags, and metafields.
collection -- A group of products with title, products, sort_by, and filters.
cart -- The shopping cart with items, total_price, item_count, and note.
customer -- The logged-in customer (null for guests) with email, orders, tags, and addresses.
shop -- Store-level data like name, url, currency, and money_format.
request -- The current HTTP request with locale, page_type, and path.
Access nested properties with dot notation: product.featured_image.src.
Filters transform output values and are chained with the pipe character. Shopify adds commerce-specific filters beyond standard Liquid:
money and money_with_currency -- Format prices using the store's currency settings.
img_url -- Generate responsive image URLs with size parameters.
asset_url and asset_img_url -- Reference files in the theme's assets directory.
link_to and url_for -- Generate anchor tags and URLs for routes, products, and collections.
strip_html -- Remove HTML tags from rich text content.
truncatewords -- Limit text to a specified number of words.
Liquid supports standard conditional and iteration constructs:
if, elsif, else, endif -- Conditional rendering based on truthiness.
unless, endunless -- Inverse conditional, useful for guard clauses.
for, endfor -- Iterate over arrays with access to forloop.index, forloop.first, and forloop.last.
case, when, endcase -- Switch-style matching for cleaner multi-branch logic.
Sections are modular, reusable Liquid components that merchants can rearrange in the theme editor. Every modern Shopify theme is built around sections.
A section file lives in sections/ and contains three parts:
- Liquid template -- The HTML and Liquid logic that renders the section.
- CSS and JavaScript -- Optional inline styles and scripts scoped to the section.
- Schema -- A JSON block that defines settings, blocks, and presets for the theme editor.
The schema is where you define the merchant-facing configuration: collection pickers, range sliders, color selectors, and text inputs that populate section settings.
Blocks are repeatable sub-components within a section. They let merchants add, remove, and reorder content units. Common block types include headings, text paragraphs, buttons, images, and product cards.
Each block gets a shopify_attributes property that you should render on the wrapper element to enable theme editor click-to-select functionality.
Snippets are partial templates stored in snippets/. Use the render tag (not the deprecated include tag) to invoke them.
Key differences from include:
render creates an isolated scope. The snippet cannot access outer variables unless you explicitly pass them.
- This isolation prevents naming collisions and makes snippets safer to reuse across sections.
- You cannot use
assign or capture to send data back to the parent template from a rendered snippet.
Name your snippets with a component-style convention: product-card, collection-filter, icon-chevron. This makes the snippets/ directory navigable as the theme grows.
Metafields let you attach custom data to products, collections, customers, and orders. In Liquid, access them through the metafields namespace on the parent object.
For simple values (single-line text, numbers, booleans), the metafield value renders directly. For complex data (JSON metafields, metafield lists, file references), you may need to iterate or parse the structured content.
Best practices for metafields in themes:
- Define metafield definitions in Shopify admin so merchants get a structured input UI instead of raw JSON.
- Use typed metafields (color, dimension, rating, date) when possible -- Shopify provides native rendering support.
- Gate rendering on metafield existence to avoid blank output when the metafield has not been populated.
Liquid executes server-side on every request, so inefficient templates directly increase time to first byte. Follow these patterns:
- Avoid nested for loops on large collections. If you need to cross-reference products and tags, pre-compute the mapping in a metafield or use the Section Rendering API to load data asynchronously.
- Use
render instead of include. Beyond scope isolation, render is cacheable by Shopify's rendering engine.
- Limit Liquid output in JSON templates. For headless or AJAX patterns, use
.json templates with minimal Liquid to produce structured data rather than HTML.
- Minimize conditional checks per product. Move complex logic into metafields or tags so the Liquid template performs a simple lookup rather than a chain of conditionals.
- Leverage lazy loading for images. Use the
loading="lazy" attribute on images below the fold and fetchpriority="high" on the hero image.
- Preload critical assets. Use the
preload link tag for above-the-fold stylesheets and fonts.
- Shopify Theme Inspector -- A Chrome extension that overlays render times on each Liquid section. Indispensable for finding slow templates.
- JSON output -- Dump any object as JSON to inspect its structure during development. Remove these before shipping.
- Theme Check -- A linter that catches Liquid anti-patterns, deprecated tags, and missing translations. Run it in CI with
shopify theme check.
- Development store preview -- Always test on a development store with representative data volume. A theme that renders fast with 10 products may crawl with 10,000.
- Using
include instead of render -- The include tag is deprecated and creates shared scope that leads to subtle bugs.
- Forgetting pagination -- Collection pages default to 50 products. Use the
paginate tag to control page size and render pagination controls.
- Hardcoding strings -- Always use translation keys via the
t filter for customer-facing text. This makes your theme translation-ready from day one.
- Ignoring the 10-second render limit -- Shopify terminates Liquid rendering after 10 seconds. Complex logic on large datasets can hit this limit.
Liquid may feel limited compared to a full programming language, but those limitations are a feature. They enforce clean data flow, encourage modular design, and keep themes fast. Master sections, snippets, metafields, and the performance patterns above, and you will be able to build any storefront experience a Shopify Plus merchant needs. If you run into an edge case that Liquid cannot handle, that is when you reach for a theme app extension or a custom app -- and we are happy to help scope that boundary.