Shopify Metafields Liquid Patterns We Use on Client Stores
Production Liquid patterns for product, collection, and shop metafields — namespaces, fallbacks, dynamic sources, and the mistakes we still fix on live client stores.
Share with Shopify developers — useful guides spread faster in theme dev communities.
Supplement brands need ingredient panels. Furniture stores need dimensions. B2B clients need spec sheets tied to variant metafields. The Liquid patterns here standardize how K2 Devworks reads metafields across verticals — after the third rescue project where namespace typos silently broke product pages.
Metafields are how Shopify themes escape hardcoded product copy without building a custom app. On client stores we use them for ingredient panels, size guides, vendor story blocks, B2B spec sheets, and merchandising badges that must stay consistent on product cards, quick view, and JSON-LD. The Liquid syntax is not hard — product.metafields.namespace.key — but production breaks when namespaces drift, fallbacks are missing, list types are looped wrong, or schema dynamic sources point at definitions merchants never filled. The patterns below are what K2 Devworks enforces on code review after 80+ metafield-heavy launches. Start with Metafields Beginner Tutorial if definitions and admin setup are new; see also product page section stacks for where metafields surface on PDPs.
Pattern 1: One namespace contract per client
Before writing Liquid we document a namespace map in the project README: custom.ingredients, custom.care_instructions, custom.badge_text, custom.spec_pdf. Merchants and content teams get the same spreadsheet. Developers who invent custom.specs on one section and custom.specifications on another create ghost bugs — the product detail tab shows specs but the collection card does not. We prefix theme-owned keys under custom unless the client already standardized elsewhere. App metafields stay read-only in theme code. When agencies inherit a store from another shop, we grep themes for metafields. and reconcile before adding new keys. Schema Guide covers dynamic source wiring; namespace discipline is the prerequisite.
Namespace map template we copy into repos
# METAFIELDS.md (client: Acme Outdoor)
# Product — namespace: custom
# | key | type | used in sections |
# |------------------|-----------------|-------------------------|
# | badge_text | single_line | product-card, main-product |
# | waterproof_rating| single_line | main-product, comparison |
# | spec_sheet_url | url | main-product |
# | feature_list | list.single_line| feature-icons (blocks) |
Pattern 2: Defensive access with blank checks
Empty metafield output is valid Liquid — merchants see nothing and assume the section is broken. We wrap every metafield-driven region in blank checks and avoid rendering empty wrapper divs that collapse layout or leave awkward padding. For optional badges we use if != blank; for required merchandising fields we show a theme-editor-only hint in comments and a sensible static fallback only in presets, not on live products. On collection templates product might be nil; on listicles article might be the object. Never copy product metafield snippets onto blog sections without changing the object. Liquid Cheat Sheet metafield examples are our quick reference during PR review.
{%- assign badge = product.metafields.custom.badge_text -%}
{% if badge != blank %}
{{ badge | escape }}
{% endif %}
{%- comment -%} Wrong — empty span still affects flex layout {%- endcomment -%}
{{ product.metafields.custom.badge_text }}
Pattern 3: list metafields in block-like UI
Merchants love feature icon rows driven by list.single_line metafields because they edit once in admin and the data appears on cards, PDP, and email templates that read the same field. In Liquid, assign the list to a variable and loop .value. Cap iterations when the design shows four icons max — {% for item in list limit: 4 %} — so a merchant who pastes twelve bullets does not break mobile grid. When icons need images, use list.metaobject_reference or separate file_reference metafields instead of hacking URLs into text lists. For section-driven icon rows that are not product-specific, blocks still win; see Flat vs Block Decision Framework.
{%- assign features = product.metafields.custom.feature_list.value -%}
{% if features != blank and features.size > 0 %}
{% for feature in features limit: 4 %}
- {{ feature | escape }}
{% endfor %}
{% endif %}
Pattern 4: metafield-backed rich content with rte class
multi_line_text_field and rich_text metafields containing HTML should render inside a div with class rte so theme typography styles apply. Do not pipe rich text through escape. Do pipe plain single-line text through escape. When merchants paste tables from Word, test overflow on mobile — we add rte table wrapper CSS scoped to the section. If the same content appears in JSON-LD, extract a stripped version or maintain a separate plain metafield for SEO to avoid schema pollution with layout HTML.
Pattern 5: file and URL metafields for downloads
B2B clients need spec PDFs and SDS sheets. file_reference metafields expose .url in Liquid. We render download links with file size hints in the label when possible — merchants upload 40MB PDFs otherwise. Always open external PDFs in a new tab with rel="noopener" when the link leaves the shop. url metafields validate in admin; still check blank before output. Pair with a section setting toggle "Show spec sheet" so merchandising can hide downloads on discontinued SKUs without deleting metafield data.
{%- assign sheet = product.metafields.custom.spec_pdf.value -%}
{% if sheet != blank %}
{{ section.settings.download_label | default: 'Download spec sheet' }}
{% endif %}
Pattern 6: collection and shop metafields
Not everything is product-scoped. collection.metafields.custom.hero_video powers collection landing banners. shop.metafields.custom.shipping_banner holds global promo copy referenced from snippets. Access syntax mirrors product. The mistake we see is using product metafields on collection templates when the data is collection-level — merchants update the collection once but the theme still loops products looking for a field that lives on the collection object. Document which templates expose which global objects. How Shopify Sections Work clarifies template context when object availability is unclear.
Pattern 7: dynamic sources in section schema
Online Store 2.0 lets merchants connect section settings to metafields in the theme editor — dynamic sources. In schema, text settings can declare compatible metafield types. In Liquid, section.settings.heading might already resolve metafield content when bound. We still write fallbacks: {% if section.settings.heading != blank %} because unbound settings stay empty. Handoff must explain which settings expect binding — otherwise merchants type duplicate copy into settings that should pull from product fields. When dynamic sources break after a metafield definition rename, settings look frozen; grep setting ids and metafield keys together during migrations. How Shopify Schema Works documents dynamic source JSON.
{
"type": "text",
"id": "subtitle",
"label": "Product subtitle",
"info": "Connect to product metafield custom.subtitle in sidebar"
}
Pattern 8: metaobjects for structured repeating data
When list metafields are too flat — each row needs image, title, body, link — metaobjects are the data model. Liquid accesses metaobject fields via .value on the reference metafield. We use metaobjects for store locators, team bios, and compatibility charts. Theme sections loop metaobject lists the same way as list metafields but with typed fields: entry.name, entry.image | image_url. Migration from hardcoded blocks to metaobjects is a content project; plan CSV import hours. Sections should tolerate empty references without throwing off layout.
Pattern 9: variant metafields for SKU-specific facts
variant.metafields.custom.dimensions matters when one product listing represents six sizes with different weights. Access via product.selected_or_first_available_variant in most product sections, or loop variants when building comparison tables — expensive, so cap variants shown. JavaScript variant pickers must re-render metafield-dependent regions on change; Liquid-only output shows first variant facts until page reload. We document which metafields are variant-level in METAFIELDS.md so developers do not read product.metafields.custom.weight when weight varies per SKU.
Pattern 10: JSON metafields — parse once, assign early
JSON metafields store structured data — nutrition facts, material percentages, FAQ arrays. In modern Shopify Liquid, typed JSON may expose properties directly; legacy patterns use | parse_json. Assign at the top of the section file for readability. Validate shape before looping — {% if nutrition.serving_size != blank %} — because merchants edit JSON in admin and typos happen. Never trust JSON keys without defaults; a missing key should not white-screen the product page.
{%- assign nutrition = product.metafields.custom.nutrition_facts.value -%}
{% if nutrition != blank %}
{% if nutrition.serving_size != blank %}
- Serving size
- {{ nutrition.serving_size }}
{% endif %}
{% endif %}
Pattern 11: metafields on product cards in collection loops
Collection loops are performance-sensitive. Reading three metafields per card across twenty-four products is fine; calling heavy nested metaobject graphs per card is not. We limit metafield reads on cards to one badge and one short text line. Deep content belongs on PDP only. Image metafields on cards use image_url with width 400 or 600 matching card layout. Theme Performance Tips applies — metafields do not bypass render cost.
Pattern 12: customer and order metafields (read-only in themes)
Logged-in customer metafields power B2B account dashboards and loyalty tiers. Access customer.metafields in account templates, not random sections, unless gated with {% if customer %}. Never expose internal customer metafields in HTML comments or JSON blobs visible to competitors. Order metafields belong on order status pages and post-purchase apps more often than storefront sections.
Pattern 13: extracting metafield logic into snippets
The same badge logic on product cards, search results, and recommended product rails must live in one snippet: {% render 'product-badge', product: product %}. Snippet parameters make dependencies explicit. When namespace changes, one file updates. Duplicated metafield access across five sections caused a wholesale client to show outdated vendor tiers for three months because one section still read legacy namespace vendor.tier. Grep is your migration tool; snippets are your prevention tool.
{%- comment -%} snippets/product-badge.liquid {%- endcomment -%}
{%- assign badge = product.metafields.custom.badge_text -%}
{% if badge != blank %}
{{ badge | escape }}
{% endif %}
Pattern 14: Theme Check and metafield definitions
Theme Check cannot know your merchant filled metafields, but it catches invalid JSON in schema and deprecated filters. We add custom CI grep for metafield namespaces used in Liquid versus METAFIELDS.md. Before launch, export products CSV with metafield columns and verify required keys are populated for top SKUs. Empty catalog metafields are a content task mislabeled as a theme bug weekly in support queues.
Pattern 15: handoff documentation merchants actually use
Developers write METAFIELDS.md; merchants get a Loom showing where to edit fields in admin product sidebar. Screenshot the metafield definition names — merchants search labels, not namespaces. Link to Shopify admin help for bulk edit via CSV when catalogs exceed fifty SKUs. When converter output infers settings from static HTML, decide explicitly which fields become metafields versus section settings — do not leave that decision to whoever converts fastest.
Pattern 16: boolean and number metafields in merchandising logic
boolean metafields drive show/hide regions — custom.is_bestseller, custom.hide_price — without duplicating section settings per product. number_integer and number_decimal metafields power comparison tables and unit pricing when paired with Liquid math. Always compare with default filters when blank: {% if product.metafields.custom.pack_size != blank %}. Do not use metafields as silent feature flags without admin documentation — merchants forget they toggled custom.clearance and wonder why badges vanished site-wide on one SKU.
Pattern 17: reference metafields and product-to-product links
product_reference metafields return a product object you can render with card snippets — related items, cross-sell upsells, spare parts. Loop list.product_reference for curated grids merchants maintain in admin. Cap loops and guard blank references. Handle sold-out related products with availability checks so PDP does not link to dead ends. Reference metafields beat scanning entire catalog loops for tag matches — performance and predictability win on large catalogs.
{%- assign related = product.metafields.custom.related_product.value -%}
{% if related != blank and related.available %}
{% render 'product-card', product: related %}
{% endif %}
Pattern 18: date and color metafields in launch campaigns
date metafields schedule badge visibility — compare with 'now' | date: '%s' carefully in Liquid timezone context. color metafields output hex for inline styles; prefer exposing swatch metafields on variant level for apparel. Campaign sections combining date metafields with section settings give merchants theme-editor control of wrapper layout while per-SKU dates stay in admin — split responsibilities deliberately.
Bulk import and metafield population QA
Launch week is not the time to discover half the catalog lacks custom.ingredients. We run CSV export/import dry runs with Matrixify or Shopify native bulk editor before theme deploy. QA samples: top revenue SKUs, longest title product, product with no image, bundle parent, variant-heavy SKU. Theme code is only half the system — empty metafields make correct Liquid look broken. Include metafield population in project timeline, not as merchant homework unless they have dedicated ops.
Metafield versioning when clients rebrand namespaces
Rebrand projects rename custom.old_key to custom.new_key across thousands of SKUs. Theme Liquid must read both during migration window or use assign fallback chain. Document sunset date for old namespace in METAFIELDS.md. One apparel client ran dual-read Liquid for six weeks while CSV migration completed — zero storefront downtime. Never big-bang namespace renames without parallel read logic and admin confirmation that import finished.
Anti-patterns we still remove on rescue projects
- Hardcoded metafield namespace strings scattered with no map — grep nightmare on migration
- Assuming metafields exist because the dev store sample product had them
- Looping all products to find metafield match instead of reference metafields
- Outputting rich text with escape filter — merchants see HTML entities
- Using text section settings for data that must sync to product cards — duplicate content drift
- Reading app-owned metafields and writing theme CSS dependent on app install order
Putting the pattern library to work
Adopt namespace map first, defensive Liquid second, snippet extraction third. Run metafield population QA on real catalog edge cases — single variant, no image, discontinued, pre-order. Pair this library with Section Schema Explained when binding dynamic sources. Metafields are the bridge between merchant data and theme presentation; discipline in Liquid access patterns prevents the bridge from cracking when catalogs scale or agencies hand off.
If the metafield namespace is not documented, it does not exist — even if Liquid renders today.
We review metafield usage on every section PR the same way we review schema labels — because empty output and duplicate namespaces generate more launch-week tickets than syntax errors. Copy METAFIELDS.md into the client Notion space, link it from the theme README, and update it when definitions change. Schema Generator helps prototype settings that will later bind to metafields; the namespace map tells you which keys those bindings target. Treat metafield Liquid as a contract, not an implementation detail.
Frequently asked questions
Should metafields live in custom namespace or app-reserved namespaces?
Use a consistent custom namespace per client — usually custom or a short brand slug — for theme-owned data. App namespaces like reviews or subscriptions belong to those apps; never write to them from theme Liquid. Document every namespace in the handoff doc.
What is the safest way to output a metafield that might be empty?
Check blank before rendering: {% if product.metafields.custom.badge != blank %}. For list metafields, check size. Never assume a metafield exists because it was filled on the sample product used during development.
Can merchants edit metafields through section settings instead of admin?
Section settings are the right surface for layout and copy merchants change weekly. Metafields are right for product-specific data that syncs across templates — ingredients, specs, compatibility tables. Use dynamic sources in schema when merchants should bind settings to metafields in the editor.
Why do metafields work in theme editor preview but show blank on live?
Usually the live product lacks the metafield, the namespace changed after a migration, or you are on the wrong template where product is nil. Test with a product that has empty metafields, not only your golden sample SKU.
How do list metafields differ from JSON metafields in Liquid?
List metafields expose .value as an array you can loop. JSON metafields return a parsed object or require parsing depending on type. Use the metafield definition type from admin — guessing types from Liquid output causes silent failures.
Topic cluster
Schema
Section schema, settings, blocks, and theme editor integration.
Convert HTML to Shopify Liquid
Paste HTML & generate Liquid with schema, blocks, and scoped CSS. No signup required.
Share
Share this guide
Found this guide useful? Share it with other Shopify developers on LinkedIn, X, or Reddit.
Authors
About the authors
Practical Shopify section workflows from the developers who build and maintain this tool.

Dhruv Goyani
3 years web design + 3 years Shopify development experience
Dhruv combines web design and Shopify theme development — converting Figma and static HTML into merchant-editable OS 2.0 sections for client stores. He focuses on schema structure, section presets, and clean handoffs between design and Liquid.
Follow Dhruv on LinkedIn
Nishad Kikani
2 years web design + 6 years Shopify development experience
Nishad has six years of Shopify theme engineering — Dawn migrations, JSON templates, performance tuning, and complex block-based sections. He leads client delivery, code review, and the production standards behind every export from HTML to Liquid Converter.
Follow Nishad on LinkedInRelated articles from our team
Editorial review
Reviewed by the HTML to Liquid Converter team


Content is reviewed by the HTML to Liquid Converter Shopify development team before publication. Technical accuracy is validated against current Shopify Online Store 2.0 conventions and active client theme work.
Last updated:
Questions or corrections? Contact us.