ThemeMergeInstall on your store

How it works

A three-way merge, explained with real theme files.

What ThemeMerge compares, why the baseline matters, how each kind of file merges, and the four ways the result leaves the app.

The three-way model

Every merge has three inputs. The baseline is the live theme as it was when the working copy was made. The live theme is where the client kept editing. The working copy is your redesign. Comparing each side against the baseline tells ThemeMerge what that side changed, and only those changes are merged.

BASELINE · OCT 2"heading": "New season""order": ["hero", "featured"]Δ liveΔ copyLIVE · DAWN"heading": "Black Friday — up to 40% off"+ sections.countdown"order": [… "countdown" …]COPY · DAWN — 2026 REDESIGN"heading": "New season essentials"+ sections.reviews"order": [… "reviews"]MERGED"heading": your decision · 1 conflict"order": ["hero","countdown","featured","reviews"]

Every file falls into one of five cases:

What changed since the baselineResult
Neither sideLeft alone. Not written.
Only liveTake live. The client’s edit carries into the merged theme.
Only the working copyKeep copy. Your edit stays.
Both, in different keys or linesMerged automatically. Both edits survive.
Both, in the same key or linesA conflict. You decide it.

Baseline vs timestamps

Without a baseline, a merge tool has two files and two modified dates. It can see that templates/index.json differs between the themes, but not whether the client changed it, you changed it, or both of you did. Attribution becomes a guess based on which theme was edited last.

SituationThree-way, with a baselineTwo-way, by timestamp
The client added a countdown section; you didn’t touch the fileTake live. No question asked.The files differ. The newer side wins, which is right only if the client edited last.
The client added a countdown; you added reviewsBoth sections kept. Zero conflicts.The whole file is a conflict. One side’s section is lost unless you merge by hand.
You deleted a section the client never touchedIt stays deleted.It looks like live added it, so it can come back.
Record the baseline when you duplicate.

Use Duplicate + record baseline in Compare themes, or Record baseline right after duplicating yourself. The second option is only correct if nobody has edited the live theme since the copy was made.

Theme-editor JSON merges key by key

templates/*.json, section groups and config/settings_data.json are parsed and merged as objects, not as text.

baselinetemplates/index.json
{  "sections": {    "hero": {      "type": "image-banner",      "settings": { "heading": "New season" }    },    "featured": { "type": "featured-collection" }  },  "order": ["hero", "featured"]}
liveclient edits
{  "sections": {    "hero": {      "type": "image-banner",      "settings": { "heading": "Black Friday — up to 40% off" }    },    "countdown": { "type": "countdown-timer" },    "featured": { "type": "featured-collection" }  },  "order": ["hero", "countdown", "featured"]}
working copyyour edits
{  "sections": {    "hero": {      "type": "image-banner",      "settings": { "heading": "New season essentials" }    },    "featured": { "type": "featured-collection" },    "reviews": { "type": "product-reviews" }  },  "order": ["hero", "featured", "reviews"]}
merged1 conflict, kept copy
{  "sections": {    "hero": {      "type": "image-banner",      "settings": { "heading": "New season essentials" }    },    "countdown": { "type": "countdown-timer" },    "featured": { "type": "featured-collection" },    "reviews": { "type": "product-reviews" }  },  "order": ["hero", "countdown", "featured", "reviews"]}

The countdown section and the reviews section are different keys under sections, so both survive. The heading is the same key changed on both sides, so it’s the only thing you decide.

Ordered arrays merge as ordered sets

A plain JSON merge treats an array as one value, so one side’s order would replace the other’s. ThemeMerge merges order and block_order as ordered sets: additions from both sides survive, each placed next to the entries it was added beside.

templates/product.json · sections.main.block_orderauto-merged
base   ["title", "price", "buy_buttons"]live   ["title", "price", "inventory", "buy_buttons"]copy   ["title", "price", "buy_buttons", "reviews_badge"]merged ["title", "price", "inventory", "buy_buttons", "reviews_badge"]

Liquid, CSS and JS merge line by line

Code files use a three-way diff3 merge. Changes to different regions of a file combine. When both sides changed the same lines, you get a hunk with four choices: live, copy, both with live first, or both with copy first. You can also edit the merged file by hand.

baselineassets/base.css
.card-grid { gap: 16px; }.card { border-radius: 8px; padding: 16px; }.button { min-height: 44px; }
live2 lines changed
.card-grid { gap: 16px; }.card { border-radius: 8px; padding: 12px; background: #fff8f0; }.button { min-height: 48px; }
working copy2 lines changed
.card-grid { gap: 24px; }.card { border-radius: 14px; padding: 24px; }.button { min-height: 44px; }
merged1 hunk to decide
.card-grid { gap: 24px; }hunk 1: .card changed on both sides.button { min-height: 48px; }

Binary assets compare by checksum

Images, fonts and other binaries are hashed. If only one side’s hash moved from the baseline, that side’s file is used. If both moved, you choose. Nothing is merged byte by byte.

Shipping the result

Four ways out. ThemeMerge never writes the live theme in any of them.

Download full theme

Pro

Every file of the merged theme as a zip. Upload it under Online Store → Themes → Add theme → Upload zip file and Shopify creates a new unpublished theme.

Download changed files

Free and Pro

Only the files that differ, plus a MERGE-REPORT.md with the exact shopify theme push --only … command.

Create merged theme

Pro · needs theme-write

Duplicates the working copy and writes the merged result into the duplicate. The original copy is untouched.

Apply to working copy

Needs theme-write

Writes the merged result into the working copy, after snapshotting it so the write can be rolled back.

About theme-write.

Writing theme files from an app requires Shopify’s Online Store protected scope exemption, reviewed per app. Until it’s granted, the two in-app options stay disabled and export is how you ship.