Problem / Solution 8 min read

Why JSON Templates Break When You Move Them Between Stores

The template worked perfectly on your build store. On the client’s store half the sections are empty. Nothing is broken — the settings point at IDs that only existed somewhere else.

TS
ThemeSync Team
WHAT A SECTION SETTING ACTUALLY POINTS ATYour section codesections/featured-collection.liquid — fully portable, works anywhere.portableThe JSON templatetemplates/index.json says this section exists, in this position, with these settings.structuralThe setting value"collection": "412698312905" — a numeric ID, not a name.store-specificOn the client storeNo record with that ID. Shopify resolves it to nothing and the section renders empty.silently blankThe code travels. The references do not.

Why this happens at all

Shopify themes separate structure from content, which is normally an advantage. A section defines how a featured collection renders; the JSON template records which collection to render and where the section sits.

The catch is how "which" gets stored. When you pick a collection in the theme editor, Shopify writes the record's identifier into the JSON:

templates/index.json — abbreviated
{
  "sections": {
    "featured": {
      "type": "featured-collection",
      "settings": {
        "collection": "412698312905",
        "products_to_show": 8
      }
    }
  }
}

412698312905 is meaningful on exactly one store. Push that file anywhere else and Shopify looks for a collection with that ID, finds nothing, and renders the section with no products. No error. No warning in the editor. Just an empty band on the page.

Why it costs you credibility rather than just time: the client's first look at the new homepage is a page with three blank sections. They aren't equipped to know that's a data reference problem, so the reasonable conclusion is that you shipped something unfinished.

Everything that doesn’t travel

Collection pickers are the most common case, not the only one. Anything a merchant selects from their own catalogue is stored as a reference.

Setting typeStored asSymptom on another store
Collection pickerNumeric collection IDSection renders with no products
Product pickerNumeric product IDFeatured product block is blank
Page pickerNumeric page IDEmpty rich-text area or dead link
Blog / article pickerNumeric blog or article IDLatest-posts section shows nothing
Metaobject referenceMetaobject GIDSection renders, all fields empty
Dynamic source (metafield)Namespace and key bindingFalls back to blank if the definition is absent
Uploaded imageFiles-API referenceBroken or missing image
App blockApp-specific block IDBlock dropped, or the template errors
Menu / link listMenu handleEmpty navigation, or falls back to main-menu

Two of these deserve extra caution.

App blocks reference a specific app installation. If the target store doesn't have the app, the block can prevent the template loading properly rather than just rendering empty — a harder failure than a blank section.

Metaobjects and metafields fail in the most confusing way, because the section renders its full layout with every field empty. It looks like a CSS bug. It isn't.

The workflow that avoids it

The root cause is building against store A and delivering to store B. Two ways out, and they suit different projects.

Option 1: build against the real store

Develop on a theme attached to the client's actual store from day one. Every collection you pick is a real collection, every product is a real product, and there's nothing to translate at the end.

This is the better default for client work, and it needs a development theme so you aren't putting unfinished work into their theme list. It also means the client reviews real content rather than placeholder data, which surfaces content problems early instead of at launch.

BUILD ELSEWHERE vs BUILD ON THE REAL STOREBUILD ON YOUR OWN STORE, MIGRATE LATERtranslation debt✗Every picker ID has to be remapped by hand✗Blank sections discovered during client review✗Metaobject and metafield definitions must berecreated✗Real content problems surface at launch⚠Sometimes unavoidable — pre-launch stores, NDAsBUILD ON THE CLIENT STORE, DEV THEMEno migration✓References are correct from the first commit✓Client reviews real products and copy✓Content gaps surface in week one, not launch week✓No theme slot spent, source stays in your repo✓Nothing to translate at handover

Option 2: migrate deliberately

Sometimes you can't build on the real store — it doesn't exist yet, or the merchant won't grant access until contracts are signed. Then migration is a task with its own budget, not a copy-paste.

  1. Push code first, configuration second. Get Liquid, CSS and JS onto the target store and confirm it renders.
  2. Strip store-specific references before pushing JSON. Better an empty picker you know about than a broken one you don't.
  3. Recreate metafield and metaobject definitions before the templates that use them. Bindings can't resolve against definitions that don't exist.
  4. Install apps before pushing templates containing their blocks.
  5. Re-pick every reference on the target store and keep a checklist so you can prove you covered them all.
  6. Screenshot every template afterwards. Empty sections are obvious in a screenshot and invisible in a diff.
Build the checklist from the JSON, not from memory. Grep your templates for picker settings and you have an exact list of what needs re-picking. Anything you don't check, the client will find.

Finding the references before your client does

Store-specific references are greppable. Long digit strings and gid:// URIs in JSON files are almost always IDs:

Locate store-specific references
# Numeric IDs in section settings (10+ digits)
grep -rnE '"[a-z_]+": "[0-9]{10,}"' templates/ config/settings_data.json

# Metaobject and other global IDs
grep -rn 'gid://shopify' templates/ config/

# App blocks embedded in templates
grep -rn '"type": "shopify://apps' templates/

Run that before a migration and you have your work list. Run it after and you have your verification. Either way, the crucial follow-up is visual: load every template and look at it. A missing product reference is a diff you'll skim past and a blank section you can't miss.

Check on mobile as well as desktop. An empty section often collapses to nothing on desktop but leaves a large gap on mobile, which is where most of the traffic is.

How ThemeSync handles this

  • You build against the client's real store from day one. A cloud development theme runs on their store with their catalogue, so pickers reference real records and there's no migration step to get wrong.
  • Templates can be sanitised before pushing. When work does have to move between stores, store-specific and dynamic references can be stripped and restored deliberately rather than pushed blind.
  • App blocks and dynamic sources are detected. Templates carrying app blocks or metafield bindings are identified up front, so you know which ones depend on store setup before you move them.
  • Template mapping makes empty sections visible. Every template is opened on the real page it applies to, so a section with nothing in it shows up during review instead of after launch.
  • Screenshot runs cover every mapped template. Capturing all templates across devices catches blank sections and mobile gaps in one pass.

Takeaways

  • Theme code is portable. Theme configuration is not — it holds IDs belonging to one store.
  • Collection, product, page, blog, metaobject, image, menu and app-block references all break when moved.
  • Failures are silent. Sections render empty rather than erroring, so the client finds them.
  • The best fix is not needing one: build against the client's real store on a development theme.
  • When you must migrate, push code first, strip references, recreate metafield definitions and install apps before pushing templates.
  • Grep for long numeric IDs and gid:// to build the work list, then verify visually on desktop and mobile.

Build on the client’s real store from day one

ThemeSync runs a development theme on your client’s actual store with their real catalogue — so section references are correct from the first commit and there’s nothing to migrate.

Try ThemeSync Free →