Post

Shopify Metafields and Metaobjects Cheatsheet

Complete guide to using Shopify metafields and metaobjects for custom data and dynamic content

A comprehensive guide to using Shopify’s metafields and metaobjects system for adding custom data to collections, products, pages, and other resources.

What Are Metafields?

Metafields are custom fields that store references or values attached to Shopify resources (Collections, Products, Pages, etc.).

Key characteristics:

  • Attached to specific Shopify resources
  • Store references to data or direct values
  • Have a namespace and key (e.g., custom.collection_links)
  • Can be single values or lists
  • Enable per-resource customization without code changes

What Are Metaobjects?

Metaobjects are structured, reusable data records that exist independently of any specific resource. Think of them as custom database tables.

Key characteristics:

  • Standalone structured data records
  • Defined by a schema (metaobject definition)
  • Reusable across multiple resources
  • Have fields with specific types (text, URL, boolean, number, etc.)
  • Can be referenced by metafields

Mental Model

1
2
Metaobjects = the "records" (reusable, structured content)
Metafields = the "pointer" that connects these records to Shopify resources

Example pattern:

1
Collection metafield → list of Metaobjects (Link items) → Liquid reads and renders

Creating Metaobjects

Step 1: Create a Metaobject Definition

A metaobject definition is like defining a database table structure.

Location: Settings → Custom data → Metaobjects → Create definition

Example: Collection Link Definition

  • Name: Collection Link
  • Type: collection_link

Fields:

  • label - Single line text (e.g., “Size guide”)
  • link - Link field (e.g., /pages/size-guide)
  • open_in_new_tab - Boolean (optional)
  • icon - File (optional)
  • sort_order - Number (optional)

Step 2: Create Metaobject Entries

After defining the schema, create actual entries:

Example entries:

  • “Shipping info” → /pages/shipping
  • “Returns” → /pages/returns
  • “Gift guide” → /blogs/gifts

Each entry is a structured object with fields, not just text.

Creating Metafields

Create a Collection Metafield

Location: Settings → Custom data → Collections → Add definition

Configuration:

  • Name: Collection Links (display name)
  • Namespace and key: custom.collection_links
  • Type: List of metaobjects (NOT single reference)
  • Metaobject definition: Select collection_link

Important: You cannot convert a single-reference metafield into a list. The type is locked once created. Create a new metafield if you need to change from single to list.

Using Metafields in Admin

For each collection, you’ll see a field “Collection links” where you can:

  • Click Select
  • Pick existing link metaobjects (or create new ones)
  • Reorder them (drag and drop)
  • Leave empty for collections that should have no links

Per-collection control:

  • Collection A: no links
  • Collection B: 3 links
  • Collection C: different set of links

Liquid Code Examples

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{% assign links = collection.metafields.custom.collection_links.value %}

{% if links != blank %}
<div class = "page-width page-width--fixed">
  <ul class = "collection-links">
    {% for link_obj in links %}
      {% assign img = link_obj.icon.value %}
      <li class = "collection-links__list-item">
        <a class = "collection-links__link" href="{{ link_obj.url.value }}">
          {% if img != blank %}
            <img src="{{ img | image_url }}" alt="{{ link_obj.label.value | escape }}" loading="lazy">
          {% endif %}
          {{ link_obj.label.value }}
        </a>
      </li>
    {% endfor %}
  </ul>
</div>
{% endif %}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{% assign links = collection.metafields.custom.collection_links.value %}

{% if links != blank %}
  <ul>
    {% for item in links %}
      <li>
        <a href="{{ item.link.url }}"
           {% if item.open_in_new_tab.value %}target="_blank" rel="noopener"{% endif %}>
          {{ item.label.value }}
        </a>
      </li>
    {% endfor %}
  </ul>
{% endif %}

Accessing Metafield Data in Liquid

Get the metafield:

1
collection.metafields.custom.collection_links

Get the value:

1
.value

Resolves into actual metaobject references you can loop through.

Access metaobject fields:

1
item.FIELDNAME.value

Each metaobject field is accessed via .value

Access Link fields:

1
2
item.link.url
item.link.title

Link fields have .url and .title properties (no .value needed)

Link Field Advantages:

  • Resource-aware: Can target a collection/product/page object, not just a string
  • Safer with handle changes: If you change a collection handle, Shopify keeps the reference intact
  • Better editor UX: Merchants pick from a selector instead of pasting URLs
  • Localization-ready: Works better with Shopify’s internal routing and multilingual setups
  • Can handle external URLs too: Link fields can store external URLs

When to Use URL Field

Use URL only when:

  • You need to allow any arbitrary external URL
  • You don’t care about resource selection
  • You’re storing something that isn’t really a “link” (e.g., webhook endpoint)
1
2
3
4
5
6
Metaobject: collection_link
Fields:
- label (Single line text)
- link (Link) ← Use this instead of URL
- open_in_new_tab (Boolean, optional)
- icon (File, optional)

Best Practices

Do’s

  1. Use metaobjects for structured data - Avoids brittle parsing
  2. Use Link field type for better resource awareness
  3. Use List of metaobjects - Allows multiple entries per collection
  4. Always check if metafield is blank before rendering
  5. Reuse metaobjects - Same objects can be used across collections
  6. Use conditional rendering - {% if links != blank %}

Don’ts

  1. Don’t hardcode collection handles in Liquid - Use metafields
  2. Don’t use separate list fields for labels and URLs - Use structured metaobjects
  3. Don’t try to convert single reference to list - Create a new metafield
  4. Don’t use blocks for per-collection data - Blocks live on templates, not collections

Complete Working Example

Metaobject Definition

Name: Collection Link Type: collection_link

Fields:

  • label - Single line text
  • link - Link
  • open_in_new_tab - Boolean (optional)

Collection Metafield

Name: Collection Links Namespace/Key: custom.collection_links Type: List of metaobjects References: collection_link

Liquid Template Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{% assign links = collection.metafields.custom.collection_links.value %}

{% if links != blank %}
  <div class="collection-custom-links">
    <h3>Helpful Links</h3>
    <ul>
      {% for link_obj in links %}
        <li>
          <a href="{{ link_obj.link.url }}"
             {% if link_obj.open_in_new_tab.value %}target="_blank" rel="noopener"{% endif %}>
            {{ link_obj.label.value }}
          </a>
        </li>
      {% endfor %}
    </ul>
  </div>
{% endif %}

Advanced Use Cases

For complex structures with grouped links:

Metaobject 1: link_item

  • Fields: label, url

Metaobject 2: link_group

  • Fields: title, items (list of link_item)

Collection metafield: references link_group (list)

This gives you structured groups per collection.

Reuse the same link metaobjects across collections (great for global links like Shipping/Returns), and only add unique ones where needed.

Common Problems and Solutions

Solution: Use metafields with conditional rendering

1
2
3
{% if links != blank %}
  <!-- render links -->
{% endif %}

Each collection has its own metafield value. Leave it empty for collections without links.

Problem: “Can only add one metaobject”

Issue: Metafield is set as single reference, not list

Solution:

  1. Go to Settings → Custom data → Collections → Your metafield
  2. Check the Type - if it says “Metaobject reference” (singular), it only allows one entry
  3. Create a NEW metafield with Type: List of metaobjects
  4. Update your Liquid to use the new namespace/key

Solution: Metafields are perfect for this - each collection has its own metafield value (its own list of link references)

Simple List Metafields

1
2
custom.link_urls (list of urls)
custom.link_labels (list of text)

Drawback: Easier to mismatch labels/urls, worse editor UX

Theme Editor Blocks

Limitation: Blocks live on the template, not on each collection. Results in multiple templates to maintain.

Hardcoded Conditional Logic

1
2
3
{% if collection.handle == 'womens-apparel' %}
  <!-- hardcoded links -->
{% endif %}

Drawback: Doesn’t scale, becomes technical debt

When NOT to Use Metaobjects

If every link set is completely unique and you’ll never reuse items, a simpler approach could be a single collection metafield with “rich text” or JSON. The tradeoff is worse editor UX and brittle parsing.

Product Metafields Example

Metafields work the same way for products:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{% assign product_links = product.metafields.custom.product_links.value %}

{% if product_links != blank %}
  <div class="product-resources">
    <h4>Product Resources</h4>
    <ul>
      {% for link in product_links %}
        <li>
          <a href="{{ link.link.url }}">{{ link.label.value }}</a>
        </li>
      {% endfor %}
    </ul>
  </div>
{% endif %}

Page Metafields Example

For pages with custom data:

1
2
3
4
5
6
7
{% assign page_data = page.metafields.custom.page_data.value %}

{% if page_data != blank %}
  <div class="page-metadata">
    <p>{{ page_data.description.value }}</p>
  </div>
{% endif %}
This post is licensed under CC BY 4.0 by the author.