Related products, spec-sheet PDFs & size-chart links as Shopify metafields — the hard types, done right.
Three metafield types break almost every bulk-import tool: list.product_reference
(related-products blocks), file_reference (spec-sheet PDFs, swatch images), and
metaobject_reference (size-chart / spec links). Each one is underdocumented, and each fails
differently — usually with no error at all. Below is the exact working format for each, a demo file with
all three, and proof it actually imports clean.
Why these three types trip up a normal import
Native Shopify CSV and most bulk-import tools handle a plain text or number metafield fine. Reference,
list, and file metafields are different: their values are IDs (gid://shopify/...), and every
ID is specific to one store. Native CSV's list format is undocumented and inconsistently
enforced; file metafields have no handle fallback at all — only a raw file ID; and a
metaobject_reference needs a metafield definition to already exist, or the value is
refused. Worst of all: when one of these silently fails, Shopify usually says the import
succeeded — the field is empty or null, discovered only later on the storefront.
list.product_reference — related products, linked products, "frequently bought together"
This is the type behind a related-products block, a "frequently bought together" row, or any field that points at a list of other products.
That's the error Shopify throws when the value shape doesn't match what a list.product_reference
expects. The undocumented part: it wants a JSON array of product handles or GIDs — not a
semicolon list, not comma-separated text, not one product per row.
["waxed-canvas-tote","recycled-wool-scarf"] — a JSON array
of the target products' handles. Each handle is resolved against your store at import time; one that
doesn't match is refused and reported to you, never silently dropped.file_reference — spec-sheet PDFs, swatch images, downloadable files
Used for a spec-sheet PDF, a size guide image, or any file attached to a product as a metafield rather than a product image.
Files have no portable handle — the value has to be the file's exact Shopify File ID. That ID is store-specific: copy one store's file ID into another store (or paste a URL, or a filename) and you get the second error above, a dangling pointer that reads as empty on the storefront.
gid://shopify/MediaImage/71302210945105 (or
GenericFile/… for a PDF) — copy it from Admin → Content → Files → select the file → Copy Media
ID. We don't yet resolve files by filename (a known v1 gap); an unknown or malformed ID is refused with a
clear reason, never guessed.metaobject_reference — size charts, spec links, structured entries
Used for a size chart, a structured spec sheet, or any link to a metaobject entry (a custom structured record you've defined in Shopify).
Two ways this breaks: the metafield definition points at the wrong (or a since-changed) metaobject definition, or the handle in your value doesn't exist. Metaobjects are handle-portable — that's the one hard type that survives a store move cleanly, as long as the destination has the same metaobject type and entry.
dod_ref_thing/relaxed-fit — <metaobject
type>/<entry handle>. Replace both sides with your own definition's type and the entry's
handle. An unmatched pair is refused, never silently dropped.The demo file — all three types, proven against a live store
One workbook, one tab per hard type, each cell showing the exact working format above. Not a mockup — every value in it round-tripped through a real Shopify store during our own build verification.
| Tab | Example value | Live import result |
|---|---|---|
| list.product_reference | ["waxed-canvas-tote","recycled-wool-scarf"] |
✓ resolved & verified |
| file_reference | gid://shopify/MediaImage/71302210945105 |
✓ resolved & verified |
| metaobject_reference | dod_ref_thing/relaxed-fit |
✓ resolved & verified |
Verified end-to-end on a live Shopify store as part of our build process — all 3 tabs imported with zero failures, zero silent drops, and a read-back match on every value. Not a live status badge; a build-time proof this file actually works before we ship it.
This exact resolution — handles and type/handle pairs turned into the right store-specific IDs, refused loudly instead of dropped silently — is what Importable, our Shopify app, does automatically on upload. It's being prepared for the Shopify App Store. Until it's available there, the demo file above shows you the exact format so you can build your own import correctly today.