Skip to content

Base propagation

How a change to the shared base theme reaches every store. See how base ⊕ overrides works in Rendering & themes.

The idea

The shared base is frozen once seeded (no-clobber), so a source change reaches stores only via an explicit, --apply-gated two-step. Because the merge is file-level, each store keeps its own overrides across the upgrade.

Editing the base — how a change gets in

The base is a theme owned by the _library tenant, and it's frozen once seeded (ensureSeededBase is no-clobber — a boot never overwrites an existing base). So editing the source .liquid/.css files in the repo does not automatically reach seeded bases or live stores — the change has to be published as a new base version on purpose. Two ways, by environment:

  • Local dev: bun run reset:local re-seeds the base library from the current source, so your edits show up. (After an object-store/DB wipe, the base self-heals on admin-api boot, or via bun run recover.)
  • Staging / prod: you can't clobber the frozen base — cut a new version instead (edit the base theme and publish, or run republish-base from source, below), then rebase stores onto it.

The rebase merge (base ⊕ overrides)

Rebasing re-anchors a store's overrides onto the new base version:

Because the merge is file-level: the base upgrade lands for every file the store did not touch, while the store's own edits survive. A file the store overrode keeps the store's version; a file it deleted stays deleted (via _deletes).

The steps

Run in a shell that has the target env's DATABASE_URL + BUNDLE_S3_*:

bash
npx tsx scripts/republish-base.ts            # dry-run → review v→v+1
npx tsx scripts/republish-base.ts --apply    # cut a new base version from code (touches no store)
npx tsx scripts/rebase-to-latest-base.ts             # dry-run → review affected stores
npx tsx scripts/rebase-to-latest-base.ts --apply     # roll stores onto it (base ⊕ overrides preserved)

Respect the release freeze

rebase --apply republishes live storefronts. Do not run it during a release freeze without an explicit go-ahead.