Local development
Set up the theme locally, run the four-process dev environment, share it safely, and debug in the browser.
Prerequisites
- Node v24.4.0, as pinned in
.nvmrc. Runnvm usein the repository root. - Shopify CLI, logged in to the store. Run
shopify auth loginonce. - Access to the
6f637e-3store, which is the myshopify handle inshopify.theme.toml.
First run
nvm use
npm install
npm run devnpm install also installs the pre-commit hook through simple-git-hooks. The hook runs Prettier over staged files.
For a fresh clone with no theme files yet, npm run onboard walks through the whole setup, including pulling a theme
from Shopify.
What npm run dev starts
npm run dev runs run-pty, which shows four panes in one terminal. Press a number key to switch panes, and press
ctrl+c twice to stop everything.
| Pane | What it does | Healthy when it says |
|---|---|---|
| vite | Vite dev server on https://localhost:5173 | ready in |
| css | PostCSS watching Tailwind input | Waiting for file changes |
| shopify | Shopify CLI theme server on port 9292 | Preview your theme |
| tunnel | Cloudflare tunnel for device testing | a trycloudflare.com URL |
Open http://127.0.0.1:9292. The Vite pane provides hot module replacement, and the Shopify pane syncs Liquid changes.
The Vite server runs over HTTPS with a certificate that vite-plugin-mkcert creates. The first run may ask for your
password to install that certificate.
Working alongside other people
The dev server in this checkout belongs to whoever started it. Before you start one, check whether port 9292 already responds:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:9292A 200 means a dev server is already running. Use it instead of starting a second one.
You cannot move npm run dev to another port. It runs run-pty ./run-pty.json, and run-pty rejects every flag except
--help and --auto-exit, so npm run dev -- --port 9293 exits with Bad flag: --port. The port is hardcoded in the
dev:shopify script in package.json.
To run a second environment from a git worktree, start the three processes yourself on free ports. strictPort in
vite.config.js pins Vite's port, so Vite needs its own port too:
npx vite --port 5174
npm run dev:css
npx shopify theme dev --environment dev --port 9293 \
--reconciliation-strategy keep-local --theme-editor-syncWhen you finish, stop only the processes you started.
Both environments in shopify.theme.toml turn on theme-editor-sync and point at the same store. Two people running
against the same development theme overwrite each other's files, so give each worktree its own unpublished theme.
To share a preview on a real device, use the tunnel pane's URL, or push to a new unpublished theme. Do not expose your own machine in other ways.
Commands
| Command | What it does |
|---|---|
npm run dev | The four-pane development environment |
npm run build | build:css then vite build. Use this, not vite build alone |
npm run typecheck | tsc --noEmit over src/**/*.ts and *.tsx |
npm run lint | Shopify Theme Check |
npm run lint:fix | Theme Check with safe fixes applied |
npm run format | Prettier over everything, including Liquid |
npm run format:check | Prettier in report-only mode |
npm run pull | Pull theme files from Shopify. Overwrites local files |
npm run push | Build, then shopify theme push, which asks which theme to overwrite |
npm run deploy | Build, duplicate the live theme, push to the duplicate |
npm run console | Liquid REPL against the dev environment |
npm run list | List the store's themes with IDs and roles |
npm run profile | Liquid render profiling for a page |
Things that catch people out
npm run dev rewrites snippets/vite-tag.liquid. While the dev server runs, that file points at localhost:5173.
Run npm run build before you commit, and check git status for the file after a dev session.
npm run pull overwrites local files. It downloads everything on the theme, including changes someone made in the
Shopify theme editor. Commit your work first.
npm run push can overwrite the live theme. shopify.theme.toml defines default and dev environments. Both
point at store 6f637e-3, and neither names a theme. With no theme named, Shopify CLI asks you to pick the theme to
overwrite, and the live theme is in that list. Run npm run list first, then name the theme explicitly with
npm run push -- --theme <theme-id>.
theme-editor-sync is on for both environments. Changes made in the theme editor on your development theme are
written back to your local files while the dev server runs. Check git status before you commit.
TypeScript passing does not mean the page works. tsc checks src/ against src/@types/global.ts, a hand-written
description of what Liquid produces. Nothing checks the Liquid side. See
Liquid to JavaScript contract.
Debugging in the browser
The theme's logger prints nothing by default. Turn it on from the console:
window.enableLogging('*'); // everything
window.enableLogging('cart,popup-logic'); // named namespaces only
window.disableLogging();It also reads a query parameter, which is easier on a phone:
https://your-preview-url/?ba_debug=*The logger saves the setting in localStorage under the BA_DEBUG key. Each createLogger('name') call defines a
namespace, so search for createLogger to find the one you want. The implementation is in src/lib/logger.ts.