The Complete Guide to Shopify Metafields (With Real Code Examples)
Metafields are the single most underused feature in Shopify. We've audited dozens of stores where merchants are paying for third-party apps to do things that metafields handle natively — size guides, ingredient lists, product badges, custom tabs. Every time, the fix is the same: strip out the app, build it with metafields, save ₹2,000-5,000/month in app subscriptions, and get a faster store.
This guide is what we wish existed when we started building on Shopify. It covers everything from basic definitions to the Liquid code patterns we use on every project at Innovatrix Infotech.
What You'll Learn
- The actual difference between metafields and metaobjects (most guides conflate these)
- Namespace conventions that keep your store maintainable at scale
- How to set metafields via Admin, Liquid, and GraphQL Admin API
- Rendering metafields in Online Store 2.0 themes with real Liquid code
- Typed metafield values: rich text, file references, product references, JSON
- Real-world patterns from our D2C builds (ingredient lists, size guides, custom badges)
Prerequisites
- A Shopify store on any paid plan (metafields work on all plans)
- A 2.0-compatible theme (Dawn, Sense, or any custom OS 2.0 theme)
- Basic familiarity with Liquid templating (helpful but not required for the admin-only sections)
Metafields vs. Metaobjects: The Distinction That Actually Matters
This is where most guides fail. They use the terms interchangeably, or they explain metaobjects as "advanced metafields." That's wrong. Here's the actual mental model:
Metafields attach custom data to an existing Shopify resource. A product metafield adds a field to a product. A collection metafield adds a field to a collection. The metafield doesn't exist independently — it's always tied to a specific product, collection, customer, order, page, or blog post.
Metaobjects are standalone data entities. They exist independently and can be referenced from multiple places. Think of them as custom content types — similar to what you'd build in a headless CMS like Directus.
Here's the rule we use on every project:
- Is it a property of a product (or collection/customer/order)? → Use a metafield.
- Is it a reusable content block that appears across multiple pages or products? → Use a metaobject.
Example: An ingredient list specific to one baby oil product? Metafield. A "Brand Story" section that appears on multiple product pages and collection pages? Metaobject.
When we built Baby Forest's Shopify store (₹4.2L launch-month revenue), we used metafields for per-product data like ingredient lists and age suitability, and metaobjects for shared content like certification badges that appeared across all products.
Namespace Conventions: The Boring Decision That Saves You Later
Every metafield has a namespace and a key, formatted as namespace.key. Shopify uses custom as the default namespace, and most merchants never change it. That's fine for a store with five metafields. It's a nightmare for a store with fifty.
Here's the convention we enforce across all client projects:
{resource_type}.{data_category}.{specific_field}
For products:
product.ingredients.full_list— Full ingredient listproduct.ingredients.key_actives— Key active ingredientsproduct.sizing.guide_pdf— Size guide documentproduct.sizing.chart_image— Size chart imageproduct.trust.certifications— Certification badgesproduct.trust.test_reports— Lab test report PDFs
For collections:
collection.display.banner_image— Collection hero imagecollection.seo.bottom_content— SEO content block below products
Why does this matter? Because six months after launch, when a merchant asks "where's the size guide metafield?", anyone on the team can find it immediately. We've inherited stores where everything lives under custom with keys like field_1, my_field, and test_field_do_not_delete. Don't be that store.
Important caveat: If you're using app as a namespace prefix, that's reserved for app-owned metafields in Shopify's ownership model. Your theme metafields should use custom or a custom namespace. Never use shopify as a namespace — that's reserved for Shopify's standard definitions.
Setting Up Metafields: Three Methods
Method 1: Shopify Admin (No Code)
This is the fastest path for store owners and content managers.
Step 1: Create the definition
Go to Settings → Custom Data → Products → Add Definition.
Name your metafield descriptively (e.g., "Ingredient List"). Choose the type — for an ingredient list, use "Multi-line text" with rich text enabled. Set the namespace and key (e.g., product.ingredients.full_list).
Critical step most guides skip: scroll down to the Access section and enable "Storefront." If you don't check this box, your metafield won't be accessible in Liquid templates or the Storefront API. We've seen developers spend hours debugging why a metafield renders as blank, only to find this checkbox was unchecked.
Step 2: Add values
Go to any product → scroll to the Product Metafields section → fill in the value.
For bulk operations (e.g., adding ingredient lists to 200 products), use a CSV import with the metafield column header format: Metafield: namespace.key [type].
Method 2: GraphQL Admin API (Programmatic)
For apps and automated workflows, use the metafieldsSet mutation:
mutation {
metafieldsSet(metafields: [
{
ownerId: "gid://shopify/Product/123456789"
namespace: "product"
key: "ingredients.full_list"
value: "<p>Aqua, Cocos Nucifera Oil, Aloe Barbadensis...</p>"
type: "multi_line_text_field"
}
]) {
metafields {
id
namespace
key
}
userErrors {
field
message
}
}
}
The metafieldsSet mutation is idempotent — it creates the metafield if it doesn't exist, or updates it if it does. This is the mutation you want for sync operations. Avoid metafieldCreate unless you specifically need to fail on duplicates.
Method 3: Liquid (Theme Code)
You don't set metafields via Liquid — Liquid is read-only. But you render them. This is where the real development happens.
Rendering Metafields in Liquid: The Patterns We Use
Basic Rendering
The simplest pattern:
{% if product.metafields.product.ingredients.full_list %}
<div class="ingredient-list">
{{ product.metafields.product.ingredients.full_list | metafield_tag }}
</div>
{% endif %}
The metafield_tag filter is the recommended approach for OS 2.0. It automatically handles type-specific rendering — rich text becomes HTML, files become links, product references become product cards.
But for full control, access the .value directly:
{% assign ingredients = product.metafields.product.ingredients.full_list.value %}
{% if ingredients != blank %}
<div class="ingredients-content">
{{ ingredients }}
</div>
{% endif %}
Collapsible Sections Pattern (Our Most-Used)
This is the pattern we deploy on almost every D2C product page. It renders metafields as expandable accordion sections:
{%- assign ingredient_list = product.metafields.product.ingredients.full_list -%}
{%- assign size_guide = product.metafields.product.sizing.guide_pdf -%}
{%- assign care_instructions = product.metafields.custom.care_guide -%}
<div class="product-info-accordion">
{% if ingredient_list != blank %}
<details class="accordion-item">
<summary class="accordion-trigger">
<span>Ingredients</span>
<svg class="icon-chevron"><!-- chevron icon --></svg>
</summary>
<div class="accordion-content">
{{ ingredient_list | metafield_tag }}
</div>
</details>
{% endif %}
{% if size_guide != blank %}
<details class="accordion-item">
<summary class="accordion-trigger">
<span>Size Guide</span>
<svg class="icon-chevron"><!-- chevron icon --></svg>
</summary>
<div class="accordion-content">
<a href="{{ size_guide.value | file_url }}" target="_blank">
Download Size Guide (PDF)
</a>
</div>
</details>
{% endif %}
{% if care_instructions != blank %}
<details class="accordion-item">
<summary class="accordion-trigger">
<span>Care Instructions</span>
<svg class="icon-chevron"><!-- chevron icon --></svg>
</summary>
<div class="accordion-content">
{{ care_instructions | metafield_tag }}
</div>
</details>
{% endif %}
</div>
The <details> element gives you accordion behavior with zero JavaScript. It's accessible, fast, and works everywhere. We stopped using JavaScript-powered accordions for metafield content two years ago and haven't looked back.
Product Badge Pattern
For stores that need dynamic badges ("New Arrival", "Best Seller", "Limited Edition"), use a metafield instead of hardcoding:
{%- assign badge = product.metafields.product.display.badge -%}
{% if badge != blank %}
<span class="product-badge product-badge--{{ badge.value | handleize }}">
{{ badge.value }}
</span>
{% endif %}
Create the metafield definition as a "Single line text" with "Limit to preset choices" enabled. Add your allowed values: "New Arrival", "Best Seller", "Limited Edition", "Sale". This gives merchants a dropdown in the admin instead of a free-text field, preventing typos and inconsistencies.
JSON Metafield for Structured Data
For complex data like a nutrition facts table or a comparison chart, use a JSON-typed metafield:
{%- assign specs = product.metafields.product.specs.technical | parse_json -%}
{% if specs != blank %}
<table class="specs-table">
<tbody>
{% for spec in specs %}
<tr>
<td>{{ spec.label }}</td>
<td>{{ spec.value }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
The JSON value would look like:
[
{"label": "Weight", "value": "200ml"},
{"label": "Shelf Life", "value": "24 months"},
{"label": "Made In", "value": "India"}
]
This pattern is enormously flexible. We've used it for everything from Ayurvedic product doshas to garment care symbols.
Typed Metafield Values: What to Use When
| Use Case | Metafield Type | Notes |
|---|---|---|
| Ingredient list | Multi-line text (rich text) | Enables bold, lists, links |
| Size guide PDF | File reference | Stores and serves the file |
| Related products | Product reference (list) | Powers "You may also like" without apps |
| Product badge | Single line text (preset choices) | Dropdown in admin, prevents typos |
| Specs / nutrition | JSON | Maximum flexibility for structured data |
| Burn time / weight | Integer / Decimal | Use with measurement for units |
| Color swatch | Color | Renders as hex value |
| Launch date | Date | Useful for "New Arrival" automation |
The most common mistake we see: using "Single line text" for everything. If your data has structure — use the structured type. Rich text for formatted content, file references for documents, product references for cross-selling. The typed system exists to prevent errors and enable better rendering.
Common Issues and Fixes
Metafield renders as blank
90% of the time, this is the Storefront access checkbox. Go to Settings → Custom Data → find your definition → ensure "Storefront" is checked under Access.
The other 10%: you're using the wrong namespace/key in your Liquid code. Copy the exact namespace and key from the definition page — don't type it from memory.
Rich text metafield outputs raw HTML
Use {{ metafield | metafield_tag }} instead of {{ metafield.value }}. The metafield_tag filter handles HTML rendering for rich text types. If you use .value, you get the raw HTML string.
Metafield doesn't appear in theme editor's dynamic source picker
This happens when the metafield type isn't supported by the specific block or section you're connecting it to. For example, you can't connect a JSON metafield to a plain text block. Check that the metafield type matches the expected input of the theme block.
Performance concerns with many metafields
Metafields loaded via Liquid are fetched as part of the product object. Having 15-20 metafields per product has negligible performance impact. We've tested stores with 30+ metafields per product and measured no meaningful difference in TTFB. The bottleneck is almost always images, not data.
However, if you're loading metafields via the Storefront API (headless builds), be selective with your fields. Request only the metafields you need using the metafield and metafields fields in your GraphQL query.
How We Use Metafields on Every Build
At Innovatrix Infotech, metafields are the first thing we configure on any new Shopify project. Before we write a single line of theme code, we map out the metafield architecture:
- Audit the product catalog — What data exists that Shopify's default fields don't capture?
- Define the namespace convention — Following the
{resource}.{category}.{field}pattern above - Choose types carefully — Rich text for content, references for relationships, JSON for structured data
- Build Liquid components — Reusable snippets that render each metafield type consistently
- Train the merchant — A 15-minute walkthrough showing where to add metafield values in the admin
For our Ayurveda and natural skincare clients, metafields typically replace 3-4 paid apps (size guide apps, ingredient display apps, product badge apps, tab/accordion apps). At ₹2,000-5,000/month per app, that's ₹8,000-20,000/month saved — and a faster store because you're not loading four extra JavaScript bundles.
As an AWS Partner, we also build automated workflows that populate metafields from external sources — syncing ingredient databases, pulling certification data from third-party APIs, or auto-generating SEO content for metafield-powered product tabs.
Want us to audit your store's metafield setup? Book a discovery call and we'll tell you exactly which apps you can replace.
Frequently Asked Questions
Written by

Founder & CEO
Rishabh Sethia is the founder and CEO of Innovatrix Infotech, a Kolkata-based digital engineering agency. He leads a team that delivers web development, mobile apps, Shopify stores, and AI automation for startups and SMBs across India and beyond.
Connect on LinkedIn