Skip to main content
Back to Blog
The Complete Guide to Shopify Liquid Objects (with Examples)
Reference

The Complete Guide to Shopify Liquid Objects (with Examples)

A practical map of Shopify Liquid objects — global objects, resource objects, the forloop object, and where each is available — with nil-safe examples and the mistakes to avoid.

12 min read

Liquid objects are the variables Shopify exposes to your theme. They hold everything from the current product to the store's currency to loop metadata. Knowing which objects exist, what data they carry, and — crucially — where they're available is the foundation of theme development.

This guide is a practical reference to the objects you'll use every day. For copy-paste snippets and a live playground, pair it with the Liquid cheatsheet; when you're ready to build, the HTML to Liquid converter wires these objects into your sections automatically.

How objects work

You output an object's value with double braces and drill into properties with dots:

{{ product.title }}
{{ product.featured_image.alt }}
{{ cart.item_count }}

Objects can represent a single value, a collection of properties, or an array you can loop over. Filters transform their output:

{{ product.price | money }}
{{ product.title | upcase }}

Global objects (available almost everywhere)

These are accessible on most templates without being passed in.

shop

Store-wide information — ideal for headers, footers, and meta tags.

{{ shop.name }}
{{ shop.currency }}
{{ shop.email }}
{{ shop.url }}

request

Context about the current request.

{{ request.page_type }}   {# e.g. "product", "collection", "index" #}
{{ request.path }}
{{ request.host }}
{{ request.locale.iso_code }}
{{ request.design_mode }}  {# true inside the theme editor #}

request.design_mode is especially useful for disabling autoplay or analytics while a merchant is editing.

routes

Locale- and market-safe URL helpers. Never hard-code paths like /cart — use these:

<a href="{{ routes.root_url }}">Home</a>
<a href="{{ routes.cart_url }}">Cart</a>
<a href="{{ routes.account_url }}">Account</a>
<a href="{{ routes.search_url }}">Search</a>

settings

Global theme settings from config/settings_schema.json.

:root { --brand: {{ settings.colors_primary }}; }

cart, customer, localization

{{ cart.item_count }} items — {{ cart.total_price | money }}

{% if customer %}Hi, {{ customer.first_name }}{% endif %}

{{ localization.country.name }} ({{ localization.country.currency.iso_code }})

Remember: customer is nil when no one is logged in, so always gate it with {% if customer %}.

Resource objects

These represent store resources. Some are global on their own template (e.g. product on a product page); others you reach through a parent.

product

<h1>{{ product.title }}</h1>
<p>{{ product.vendor }} · {{ product.type }}</p>
<p>{{ product.price | money }}</p>
{% if product.compare_at_price > product.price %}
  <s>{{ product.compare_at_price | money }}</s>
{% endif %}
<a href="{{ product.url }}">View</a>

Key properties: title, price, compare_at_price, available, vendor, type, tags, handle, url, description, featured_image, images, media, variants, options_with_values, selected_or_first_available_variant, metafields.

variant

{% assign variant = product.selected_or_first_available_variant %}
{{ variant.title }} — {{ variant.price | money }}
SKU: {{ variant.sku }}
Available: {{ variant.available }}

collection

<h1>{{ collection.title }}</h1>
<p>{{ collection.products_count }} products</p>
{% for product in collection.products %}
  {{ product.title }}
{% endfor %}

collection.products returns up to 50 products per page — wrap it in {% paginate %} for larger collections.

cart and line_item

{% for item in cart.items %}
  {{ item.product.title }} — {{ item.quantity }} × {{ item.price | money }}
{% endfor %}

Content objects: blog, article, page

{{ article.title }}
{{ article.author }}
{{ article.published_at | date: "%B %d, %Y" }}
{{ article.content }}

metafields and metaobject

Custom data attached to a resource. Always read the typed value with .value:

{{ product.metafields.custom.subtitle.value }}

{% assign designer = product.metafields.custom.designer.value %}
{{ designer.name.value }}

You can also access metaobjects directly by type and handle:

{{ metaobjects.testimonials.homepage.title.value }}

The forloop object

Inside a for loop, Shopify gives you a forloop object with loop metadata:

{% for product in collection.products %}
  {{ forloop.index }}   {# 1-based position #}
  {{ forloop.index0 }}  {# 0-based position #}
  {{ forloop.first }}   {# true on first iteration #}
  {{ forloop.last }}    {# true on last iteration #}
  {{ forloop.length }}  {# total iterations #}
{% endfor %}

This is how you add "first"/"last" classes, alternate rows, or close a wrapper after the final item. There's a matching tablerowloop object inside {% tablerow %}.

Where objects are available (scope)

Not every object exists on every template — this trips up beginners constantly.

  • product is global on product templates; elsewhere you reach a product through a parent (collection.products, cart.items[i].product, a product setting).
  • collection is global on collection templates.
  • article/blog are global on article/blog templates.
  • section and section.settings exist inside a section; block and block.settings exist inside a block loop.
  • cart, shop, request, routes, settings, customer, localization are effectively global.

If an object is nil where you expected data, the first thing to check is whether you're on the right template — or whether you need to pass it explicitly into a snippet with {% render %}.

Nil-safety and common mistakes

  • Guard optional objects: {% if customer %}…{% endif %}, {% if product.featured_image %}…{% endif %}.
  • Use default for fallbacks: {{ product.vendor | default: "Unknown" }}.
  • Read metafields with .value — outputting the metafield object directly is the legacy behavior; .value is the documented, type-aware way.
  • Don't hard-code URLs — use routes and product.url/collection.url so links stay correct across locales and markets.
  • Prices are in cents — always pipe through money, never print cart.total_price raw.
  • Snippets have isolated scope — {% render %} does not inherit parent variables; pass what you need explicitly.

Put objects to work

The fastest way to see objects in action is the Liquid cheatsheet, which renders each one against mock Shopify data in a live playground. When you build a section, the HTML to Liquid converter maps your content onto these objects and settings for you. And to make that content editable, see our guide on converting HTML into a Shopify section and the section schema reference.

Conclusion

Objects are the data layer of every Shopify theme. Learn the global ones (shop, request, routes, settings, cart, customer), the resource ones (product, variant, collection, article), and the loop helpers (forloop), keep scope and nil-safety in mind, and you can read and render any store data with confidence.

Next: browse the full cheatsheet, generate a section schema, or convert your first block of HTML with the free tool.

Found this helpful?

Share it with your network!

Ready to Convert HTML to Liquid?

Try our free HTML to Liquid converter and build your Shopify themes faster.

Try HTML2Liquid Now