Use metafields in Liquid
After a metafield is created, you can read and display its value in your theme with Liquid. This guide covers the access syntax, how to render each metafield type, and how to handle missing values.
For what metafields are and how they're structured, see Overview. For the full list of types, see Types.
Access a metafield
Access a metafield through its parent resource, namespace, and key:
{{ resource.metafields.namespace.key }}
- Parent resource — the object the metafield is attached to. In Liquid you read metafields from objects that expose a
metafieldsproperty, reached through the relevant page:producton a product page andcollectionon a collection page. Whether an object exposesmetafieldsis listed on that object's reference page. - Namespace — a container that groups related metafields so their keys don't collide (for example,
custom). - Key — the metafield's own name (for example,
spec_text).
This returns a metafield object, not the stored value. To output the value, append .value.
For example, suppose a product has a single_line_text_field metafield named spec_text in the custom namespace, holding 100% cotton:
{{ product.metafields.custom.spec_text.value }}
100% cotton
🚧 Caution
Accessing a metafield always returns a metafield object, even when the metafield doesn't exist — the result is never
nil. Test.valuefor presence, not the metafield itself. See Handle missing values.
Render each type
How you read .value depends on the metafield type. Each example below assumes the product has the named metafield in the custom namespace.
Text, number, date, boolean, color, and URL
These scalar types return the value directly from .value. For example, the spec_text single-line text field above (100% cotton):
{{ product.metafields.custom.spec_text.value }}
100% cotton
The same pattern applies to multi_line_text_field, number_integer, number_decimal, date, date_time, boolean, color, and url.
JSON
For a json metafield, .value is a parsed object. Access nested properties by name. Suppose details_json holds {"foo": "bar"}:
{{ product.metafields.custom.details_json.value.foo }}
bar
Measurement (weight, volume, dimension)
These return a measurement object. Read the number and unit separately. For a weight metafield net_weight holding 20 kilograms:
{{ product.metafields.custom.net_weight.value.value }} {{ product.metafields.custom.net_weight.value.unit }}
20 KILOGRAMS
Rating
A rating metafield returns a rating object. For a review_score rated 4 on a scale that tops out at 10:
{{ product.metafields.custom.review_score.value.value }} / {{ product.metafields.custom.review_score.value.scale_max }}
4 / 10.0
File (image)
A file_reference metafield holds the file under value.image. For a spec_file holding an image, output the image URL directly, or pass value to the img_url filter to resize it:
<img src="{{ product.metafields.custom.spec_file.value.image.src }}">
<img src="{{ product.metafields.custom.spec_file.value | img_url: '400x' }}">
Handle missing values
Because accessing a metafield never returns nil, guard your output on .value:
{% if product.metafields.custom.spec_text.value != blank %}
<p>Material: {{ product.metafields.custom.spec_text.value }}</p>
{% endif %}
Render with metafield filters
Instead of reading .value and building the markup yourself, the metafield_tag and metafield_text filters output a metafield based on its type:
metafield_tagwraps the value in an HTML element suited to the type, with ametafield-<type>class — ready to drop into the page.metafield_textreturns the value as plain text, for when you need the raw string.
For the spec_text field above (100% cotton):
{{ product.metafields.custom.spec_text | metafield_tag }}
{{ product.metafields.custom.spec_text | metafield_text }}
<span class="metafield-single_line_text_field">100% cotton</span>
100% cotton