Problem / Solution 8 min read

Dynamic Sources and Metafields: Why the Theme Looks Broken Elsewhere

The section renders. The layout is perfect. Every field inside it is empty. This is the most confusing failure in Shopify theme work, and it is almost never a CSS bug.

TS
ThemeSync Team
THE CHAIN A DYNAMIC SOURCE DEPENDS ON1. The section schemaDeclares a setting that accepts a dynamic source. Lives in your theme, fully portable.in the theme2. The bindingThe template records that this setting reads product.metafields.specs.material.in the theme3. The metafield definitionNamespace specs, key material, with a type. Lives on the store, not the theme.on the store4. The valueThis particular product actually has something entered for that field.per recordMissing 3 or 4?Section renders its full layout with nothing inside. No error anywhere.blankBreak any link and the section still renders β€” just empty.

Why this failure is so hard to diagnose

Most theme bugs announce themselves. Liquid errors print. Missing assets 404. Broken CSS looks broken.

A missing dynamic source does none of that. Shopify resolves the binding, finds nothing, and renders an empty string. Your section markup is present and correctly styled β€” headings, spacing, grid, the works β€” with no content in it.

So the symptom is a beautifully laid out empty box. Developers reach for the inspector and start debugging CSS, because that's what an empty box usually means. The actual cause is two layers away, on the store, in a settings screen nobody opened.

Fastest way to tell them apart: view source. If the element exists in the DOM with no text inside, it's a data problem. If the element isn't in the DOM at all, it's Liquid or a conditional. That one check saves an hour.

Where it usually bites

  • Moving a theme between stores. Definitions don't come along, so every bound field goes blank at once.
  • Building on a demo store. You created the definitions on your store. The client's store has never heard of them.
  • New products. Definition exists, product has no value. One product looks broken, the rest are fine β€” which reads like a caching bug.
  • Someone deleted a definition. Deleting a metafield definition takes its values with it. Every product using it silently empties.

The four things that all have to exist

A dynamic source only renders if all four links hold. Two live in your theme and travel with it. Two live on the store and don't.

LinkLives inTravels with the theme?If missing
Section schema settingTheme codeYesSetting isn't offered in the editor
The binding in the templateTemplate JSONYesFalls back to the static value
Metafield definitionStore settingsNoRenders empty
Value on the recordThe product / pageNoRenders empty for that record only

Metaobjects add a fifth: the metaobject definition, plus the entries themselves. A section bound to a metaobject on a store where that definition doesn't exist renders its whole layout with every field blank β€” the most complete version of this failure.

A binding in templates/product.json
{
  "sections": {
    "specs": {
      "type": "spec-table",
      "settings": {
        "heading": "Specifications",
        "material": "{{ product.metafields.specs.material }}",
        "care": "{{ product.metafields.specs.care_instructions }}"
      }
    }
  }
}

The theme is fine. Whether anything renders depends entirely on specs.material existing on the target store and having a value on this product.

Diagnosing it in under five minutes

Work down the chain in order. Each step rules out a layer.

  1. View source. Element present but empty confirms a data problem, not CSS.
  2. Check the definition exists. Settings › Custom data on the store. Confirm namespace and key match the binding exactly β€” specs.material is not spec.material.
  3. Check the value on this record. Open the specific product and look at its metafields. Empty explains one broken page while others work.
  4. Check the type matches. A setting expecting single-line text bound to a rich-text or list metafield can render nothing or render markup as literal text.
  5. Try a second record. If product B renders and product A doesn't, it's values. If neither renders, it's the definition.
Find every binding in the theme
# All metafield bindings in templates and settings
grep -rn 'metafields\.' templates/ config/settings_data.json sections/

# Metaobject references
grep -rn 'gid://shopify/Metaobject' templates/ config/

That grep is your dependency list. Every namespace and key it returns has to exist on the target store before those templates will render anything.

Turn it into a document. A short table of every metafield the theme needs β€” namespace, key, type, which template uses it β€” is the single most useful handover artifact for a metafield-driven theme. It's also what makes the work look considered rather than fragile.

Building metafield-driven themes that don’t collapse

Dynamic sources are worth using β€” they're how you give a merchant structured content without hard-coding copy into templates. The trick is not letting a missing value look like a broken page.

ORDER OF OPERATIONS FOR METAFIELD-DRIVEN WORK1Define firstCreate definitions on thestore that will actuallyrun the theme, beforebuilding sections.on the store2PopulateGet real values onto realrecords. Placeholdercontent hides length andwrapping problems.real data3BindPoint section settings atthe sources, with asensible static fallbackwhere the schema allows.fallbacks4QA both statesCheck a record with valuesand one without. Emptymust degrade gracefully,not look broken.with & withoutDefinitions and values first. Templates last.

Guard for the empty case in Liquid

Don't render section furniture for content that doesn't exist. A heading above nothing is worse than no section:

Degrade gracefully instead of rendering an empty shell
{%- liquid
  assign material = section.settings.material
-%}
{%- if material != blank -%}
  <div class="spec-row">
    <dt>Material</dt>
    <dd>{{ material }}</dd>
  </div>
{%- endif -%}

Apply the same idea at section level: if every field is blank, render nothing at all rather than a titled empty container. A merchant adding a product without filling in specs then gets a clean page instead of a bug report.

The content-length trap. Real metafield values are longer and messier than your placeholders. Test with the longest value in the catalogue, not a tidy example. "Material" wrapping to three lines on mobile is a layout bug you only see with real data.

Setting client expectations about structured content

Metafield-driven sections shift work onto the merchant, and that needs saying out loud before launch rather than after.

The failure mode is predictable: you deliver a spec table that reads from metafields, the merchant adds forty products without filling them in, and three months later you get an email saying the theme is broken.

"The specifications section reads from custom fields on each product, which means you control that content without needing us. The trade-off is that a product with those fields empty won't show a spec table. I've set it so an empty field hides cleanly rather than leaving a gap, and I'll send a one-page note listing which fields drive which sections."

Two things this buys you: the merchant understands the mechanism, and you've pre-empted a support conversation that would otherwise arrive as a complaint. If you handle sign-off formally, it's worth capturing "content fields populated" as its own item rather than folding it into design approval.

How ThemeSync helps here

  • You build against the store that will run the theme. A development theme on the client's real store means definitions and values are the real ones from the first commit β€” there's no store to migrate away from.
  • Dynamic sources are detected in your templates. Templates carrying metafield bindings or metaobject references are identified, so you know which depend on store setup before moving or publishing them.
  • Template mapping previews on real records. Each template opens on the actual product or page it applies to, so a blank spec table shows up during review rather than after launch.
  • Screenshot runs cover every mapped template across devices. Empty sections and long-value wrapping are obvious in a capture and invisible in a diff.
  • Client feedback is pinned to the element. "This box is empty" arrives attached to the exact section and viewport, so you're not reproducing it from a description.

Takeaways

  • An empty-but-styled section is a data problem. View source: element present and blank means the binding resolved to nothing.
  • Metafield and metaobject definitions live on the store and don't travel with a theme. Bindings do.
  • All four links must hold: schema setting, binding, definition, value. Break any one and it renders empty.
  • Grep for metafields. and gid://shopify/Metaobject to get an exact dependency list.
  • Create definitions and populate real values before building the sections that read them.
  • Guard the empty case in Liquid so a missing value hides cleanly instead of leaving a titled void.
  • Test with the longest real value in the catalogue, not a tidy placeholder.
  • Tell the merchant which fields drive which sections, in writing, before launch.

Catch empty sections before your client does

ThemeSync builds on the client’s real store, flags templates that depend on metafields and metaobjects, and captures every template across devices so blank sections surface in review.

Try ThemeSync Free →