Shopify
Shopify metaobjects for production catalogues in 2026
Shopify metaobjects are how I now keep size charts, fabric stories and lookbook cards as reusable catalogue entries instead of HTML inside a product description. I am Alan Vo, a Gold Coast web developer. I have spent 18 years shipping storefronts. Fashion and jewellery work is where this model earns its keep: merchandisers want one size table reused across a colour family, and buyers still need that table on the PDP.
This is not another product metafield. Shopify's metaobjects overview is explicit. A metafield adds a column to an existing resource. A metaobject is a standalone record with several related fields. You reference it from products. If you paste the same care copy into fifty descriptions, you will ship fifty drift copies and no draft state.
I write this as a 2026 production note for catalogues I actually ship. Combined listings solve the colour switch. Metaobjects solve the structured content beside that switch: size, material, origin, lookbook. They belong on Online Store themes and on a Storefront API catalogue. They are not a replacement for variants.
Why Shopify metaobjects matter on a live catalogue
Shopify metaobjects matter on a live catalogue because size, fabric and lookbook copy is a record, not a paragraph. A product metafield is the right tool for one extra string on that SKU. The moment the same chart has to appear on twenty SKUs, you need a row you can edit once.
Shopify's data modelling guide maps this to tables and foreign keys. The definition is the table. The entry is the row. A metaobject_reference or list.metaobject_reference metafield is the foreign key. Do not store a handle in a plain text field and hope Liquid can join it. That breaks the connection and burns unique-handle lookups on every render.
The merchant path matches the API. The Help Centre metaobjects page puts definitions under Settings, Custom data, and entries under Content, Metaobjects. I use the same shapes they list: product highlights, FAQs, size charts, jewellery care. Shopify's Standard Product Taxonomy also stores category attributes as metaobject entries. Colour swatches on a Horizon PDP are often those standard entries, not a custom CSS file.
The 2026 reason to do the work now is Horizon plus high-variant Liquid. If you are already rebuilding the option picker, stop stuffing size HTML into the description. Put the chart in a metaobject and let a theme block bind the fields, the same discipline I want on a Horizon theme migration.
I reach for this on fashion, jewellery and interiors, not on a 40-SKU gift shop that never reuses a table. The cost only pays when editors will update the same structured content on many SKUs.
How Shopify metaobjects actually work
Shopify metaobjects actually work as a definition that names the type and fields, then entries that hold the values, then a metafield that points a product at those entries. App-owned types use the $app prefix in GraphQL and the app prefix in shopify.app.toml. Merchant-owned types use any non-reserved prefix, such as size_chart. Merchant-owned entries are what merchandisers edit in admin.
Create the definition first. For merchant-owned size charts I use metaobjectDefinitionCreate with field keys such as size, chest_inches and waist_inches, matching Shopify's own example. Then metaobjectCreate writes a row. The manage entries guide is the mutation list I keep open. Field keys must match the definition. You cannot change type after create. UNDEFINED_OBJECT_TYPE and OBJECT_FIELD_REQUIRED are definition mistakes, not theme bugs.
Access is two switches. access.admin controls Shopify admin and the Admin API. access.storefront controls the Storefront API. PUBLIC_READ is for Hydrogen. Liquid themes can read metaobjects even when storefront access is NONE. A theme that works and a Hydrogen query that returns empty is usually this switch, not a missing token.
Capabilities change storefront behaviour. Shopify's capabilities guide names four: publishable (DRAFT/ACTIVE, drafts are nil in Liquid), translatable, renderable (SEO and sitemap), and onlineStore (a theme template and URL prefix such as /pages/content/{handle}). onlineStore is GraphQL only, not TOML. The metaobject theme template lives at templates/metaobject/{type}.json and starts empty.
On the theme, the global object is metaobjects, not shop.metaobjects. Shopify's performance note marks shop.metaobjects as deprecated. A single entry is metaobjects.type.handle. Field values need .value. A list on the product is a metafield loop: {% for highlight in product.metafields.custom.active_highlights.value %}. Use file_reference so image_url works. Use metaobject_reference so Liquid resolves the related object without a second lookup.
Limits I treat as hard. Shopify's metaobject limits allow 128 merchant definitions on Basic, Shopify and Advanced, and 256 on Plus and Enterprise. Each installed app can create 128 of its own. Each definition can have 40 fields and 1,000,000 entries. Standard taxonomy definitions do not count. Liquid handle lookups are capped at 20 unique handles per page and cannot paginate. metaobjects.TYPE.values can. An unpaginated for loop still stops at 50. The paginate tag walks values up to 250 per page. Use values for lists. Use a handle only when you need one named entry.
The Storefront API in the 2026-07 Metaobject object needs unauthenticated_read_metaobjects. Query one entry by GID or by handle plus type. onlineStoreUrl is null unless onlineStore is on. Shopify Functions can read app-owned $app types in input queries. Merchant-owned types do not work there. Catalogue content stays on the product reference.
Production checklist
The production checklist starts with the definition, then storefront access, then entries, then the product metafield, then the theme.
- Decide merchant-owned versus app-owned. Editors who live in admin get a merchant-owned type. An app that must own the schema uses
$appand TOML. - Create the definition before any entry. Confirm type, field keys, validations and the display name field. Forty fields is the documented ceiling.
- Set storefront access. Leave it
NONEif only Liquid will read. SetPUBLIC_READif Hydrogen will query. - Enable
publishableif merchandisers need draft rows. Enabletranslatableon any extra locale. EnablerenderableandonlineStoreonly if the entry is a public page. - Create entries with
metaobjectCreateor in Content, Metaobjects. Record GIDs for PIM jobs. Lock handles if you will look them up in Liquid. - Add a product metafield of type
metaobject_referenceorlist.metaobject_reference. Attach one size chart as a single reference. Highlights are a list. - In the theme, bind through the product metafield. Do not loop
metaobjects.TYPE[handle]inside a collection grid. - Use
metaobjects.TYPE.valueswithlimitorpaginatefor index pages. Twenty unique handle lookups per page is a hard cap. - Read fields with
.value. Treat a blank reference as missing merchandising, not a Liquid crash. - If
onlineStoreis on, add sections totemplates/metaobject/{type}.json. An empty default template is a blank URL. - Re-test Combined Listings colour switches, predictive search and the Shopping feed. Metaobject copy is not a feed column unless you map it.
- Brief merchandisers: edit the entry for copy, edit membership on the product metafield, never paste the same table into the description again.
What breaks
Handle lookups that exceed twenty unique handles per page are the first thing that breaks. Shopify's metaobject definition Liquid object documents the cap. A loop of metaobjects.faqs[item.handle] on a busy PDP will throw Exceeded maximum number of unique handles. Switch to values or to a product metafield list.
Theme loops that walk every metaobject on a collection page are the second. Each entry access hits the backend. An unpaginated loop yields at most 50. Pagination multiplies the work. Limit a homepage testimonial loop to three. Put size data on the product, not on a global loop of every chart.
Storefront access is the third. Liquid can look fine while Hydrogen returns nothing. PUBLIC_READ is the Storefront API switch. Draft publishable entries are nil in Liquid. I have watched a missing size chart ticket that was a draft row, not a theme regression.
Ownership is the fourth. TOML definitions are read-only in the Admin API. You cannot change type after create. App-owned function queries cannot see merchant-owned types.
SEO is the fifth. onlineStore pages need renderable fields and a template with sections. Do not 301 product URLs at a metaobject page. The product remains the indexable document, which I wrote up in canonical URLs for ecommerce catalogues. Collection SEO still belongs on the collection object, covered in Shopify SEO for collection and product pages.
Markets are the sixth. Translate the entry, then load the PDP on that market's domain. A size chart that stays English on a French market is a missing translation. Apps that still inject size HTML into .product-description leave you with two tables. Remove the injector.
How I measure Shopify metaobjects in production
I measure Shopify metaobjects in production on render quality, TTFB, translation and reuse, not on a claimed conversion lift. Render quality first. On a product that references a size chart, does the table print the entry fields, and does a sibling colour that shares the same reference still show it after a Combined Listings switch? If the chart vanishes on the child URL, the reference lives on the parent only.
Speed second. I compare TTFB on a PDP that binds one product metafield list against a PDP that loops metaobjects.TYPE.values. If first paint walks fifty FAQ rows to render three, the loop is the ticket.
Discovery third. If onlineStore is off, Search Console should not grow /pages/{urlHandle}/{handle} URLs. If it is on, those URLs need renderable titles and a template that is not empty.
Reuse fourth. Change one measurement on an entry and confirm every attached SKU updates. If only one product moves, someone stored text, not a reference.
I do not invent a conversion percentage for a metaobject cutover. The published figure I will cite is still the Their Nibs Shopify rebuild: 31% more conversions and 48% more orders after a purchase-path rebuild. That was theme and journey, not a size-chart type.
Related work on this site
Fashion and jewellery catalogues are where Shopify metaobjects pay rent, because size, material and lookbook copy has to be reused across colour SKUs. The Tamannaah Fine Jewellery Shopify Plus storefront needs care and metal stories that stay consistent when the stone changes. The Cecilie Bahnsen fashion storefront needs a size system that is not rewritten per colour. Their Nibs is the rebuild where the purchase path had to stay first while merchandising stayed editorial. All three were contract development on an agency team. If you are already on Combined Listings, read Shopify Combined Listings on production catalogues next to this note. The colour switch and the size chart are shared work.
FAQ
What are Shopify metaobjects for if I already have product metafields?
Shopify metaobjects are for reusable structured records with several fields, not for one extra string on a SKU. Keep a product metafield for a one-off attribute. Use a metaobject when the same size chart or highlight must be edited once and referenced from many products.
Do Shopify metaobjects replace Combined Listings on a colour catalogue?
Shopify metaobjects do not replace Combined Listings. Combined listings group child products so the buyer can switch colour on one PDP. Metaobjects hold the structured content those children share. Use both when colour is a product and size is a table.
How do I show Shopify metaobjects on a Horizon product page?
You show Shopify metaobjects on a Horizon product page by referencing the entry from a product metafield, then connecting that metafield to a block or printing .value in Liquid. PUBLIC_READ is for the Storefront API. Liquid can read without it. Draft publishable entries will not render.
Can guests see draft Shopify metaobjects on the storefront?
Guests cannot see draft Shopify metaobjects when the publishable capability is on. Liquid returns nil for a draft handle and skips drafts in values loops. Publish with metaobjectUpdate and status: ACTIVE before you call the PDP live.
Keep reading
Contact if you want this kind of work on a live store.