There’s no rollback for a metaobject import. Once a value is overwritten, the old one is gone unless you saved it first, and Shopify’s help docs say plainly that deleting an entry can’t be undone. So “we’ll fix it if something goes wrong” really means “we’ll retype it from memory”.
A usable backup is three things, not one: the definition (the schema), the entries (the data), and the references on products and collections that point at those entries. CSV handles the second very well and the first badly. Here’s how to back up all three, and the restore steps for the three situations you’ll actually face.
What a backup has to cover
| Part | What’s in it | Best format | Why it matters |
|---|---|---|---|
| Definition | Type, name, field keys and types, required flags, validations, capabilities, access, display-name field | JSON | Without it you can’t recreate the schema that the entries need |
| Entries | Handle, every field value, status | CSV, one file per definition | The data itself; what most people mean by “backup” |
| Inbound references | Which products and collections point at which entries | CSV keyed by handles | Deleting an entry removes it everywhere it’s used; recreating it doesn’t put those links back |
The third row is the one people forget. Shopify’s help docs are explicit: when you delete an entry, it’s removed from anywhere it’s published or used in your store. Recreate it from a backup and it gets a new ID, so every product that used to point at it is now pointing at nothing.
Back up entries as CSV
One export per definition, named so you can find it later:
text
backups/
2026-10-12/
size_guide-2026-10-12.csv
care_instructions-2026-10-12.csv
designer-2026-10-12.csv
definitions-2026-10-12.json
product-references-2026-10-12.csv
When to take one:
- Before every import. No exceptions, including “small” ones.
- Before a theme or app change that touches custom data.
- On a schedule for definitions that several people edit in the admin.
Check each export when you take it: it opens cleanly, the handle column has no blanks, and the number of rows matches the number of entries the admin shows for that definition. A backup you haven’t opened is a hope, not a backup.
Back up definitions as JSON, not CSV
A definition is nested: fields have validations, the definition has capabilities and access settings. Flattening that into a CSV loses information, so save it as the JSON the API gives you:
graphql
query DefinitionsBackup {
metaobjectDefinitions(first: 50) {
nodes {
type
name
description
displayNameKey
access { admin storefront }
capabilities {
publishable { enabled }
translatable { enabled }
renderable { enabled }
onlineStore { enabled }
}
fieldDefinitions {
key
name
description
required
type { name }
validations { name value }
}
}
}
}
Save the response as definitions-YYYY-MM-DD.json. If you have more than 50 definitions, page through with after.
Two notes on ownership:
- App-owned definitions (types starting
$app:) can be declared in your app’sshopify.app.tomland kept in version control. That file is already a backup. - Merchant-owned definitions (the ones created under Settings > Custom data) can’t be declared in TOML; Shopify creates them through the admin or the GraphQL API only. The JSON export is their backup.
Back up the references that point at entries
If products point at entries through a metafield (for example custom.size_guide), export that relationship in a form that survives a restore: the product’s handle and the entry’s handle, not their IDs.
csv
product_handle,metafield,entry_type,entry_handle
slim-fit-chinos,custom.size_guide,size_guide,northline-slim-trousers
denim-jacket,custom.size_guide,size_guide,northline-regular-jackets
linen-shirt-blue,custom.care,care_instructions,linen-cool-wash
Your product export tool or a short API script can produce this. With handles on both sides, you can re-link products to entries on the same store or a new one.
Restore A: a bad import on the same store
The most common case. An import wrote wrong values into existing entries.
- Find the last good export, the one taken right before the bad import.
- Re-import it. Every row’s handle matches an existing entry, so every entry is updated back to its saved values. One exception to check: fields that were empty in the backup but filled by the bad import. If your tool skips empty cells instead of clearing the field, clear those by hand.
- Remove the extras. Re-importing doesn’t delete entries the bad import created. Export the definition now, put the good file in a sheet named
Before, and flag handles that weren’t in it with=COUNTIF(Before!A:A,A2)=0. EveryTRUEis an entry that didn’t exist before the bad import. Delete those in the admin, or with the API’smetaobjectDeleteif there are many. - Check the storefront on a few pages that use the restored data.
Restore B: entries were deleted
Deleted entries can’t be undeleted, so they have to be recreated:
- Import the entries from the backup CSV. Their handles no longer exist, so each row creates a new entry with the same handle and field values.
- Re-link products using the references backup. The recreated entries have new IDs, so every product metafield that pointed at the old ones has to be set again, by handle.
- Check list fields specifically. A list reference that contained a deleted entry has lost that item; re-add it.
Restore C: moving to a new or cloned store
Order matters, because references can only point at things that already exist:
- Definitions, recreated from the JSON backup.
- Products, collections and files, with the same handles as the source store.
- Entries that don’t reference other entries (size-chart rows, materials, designers).
- Entries that reference other entries (charts that use rows, collection stories that use designers).
- Product and collection metafields that point at entries, from the references backup.
Use handles all the way through. GIDs from the old store don’t exist on the new one; handles do, as long as you created things with the same handles. GIDs vs handles explains why this is the only approach that survives a move.
Run a restore drill once
The first time you restore shouldn’t be during an incident. On a development store:
- Take a full backup: definitions, entries, references.
- Break something on purpose. Import a file with a wrong column; delete three entries.
- Restore, following the steps above.
- Time it, and write down every step that wasn’t obvious.
Most teams find their gap in step 1: the definition or the references were never backed up, only the entries. Better to find that on a dev store.
For the checks that stop most restores from being needed, see catching bad metaobject data before import. For how definitions, entries and references fit together in a well-structured store, see the guide to structuring custom data on Shopify.