Dev server will not start
npm run dev fails, the preview will not load, or hot module replacement has stopped working.
Dev server will not start
Use this runbook when npm run dev fails, when one of the four processes exits, when the Cloudflare preview URL returns
an error, or when changes to src/ stop reaching the browser.
Four processes run under run-pty. Press ctrl+z for the dashboard and 1 to 4 to read each one's output. The
failing process is usually obvious once you look at its own screen rather than the combined view.
Diagnose
1. Identify which process failed
| Process | Healthy output |
|---|---|
| vite | ready in and a https://localhost:5173 URL |
| css | Waiting for file changes |
| shopify | Preview your theme |
| tunnel | A trycloudflare.com URL |
run-pty.json marks each of these, so the dashboard shows a green dot for a healthy process.
2. Check the Node version
node --version
cat .nvmrcThey should match. .nvmrc pins 24.4.0.
3. Check Shopify CLI authentication
shopify theme list --store a-sales-affairAn authentication error here explains a failing shopify process.
4. Check the ports
lsof -i :5173
lsof -i :9292A previous run that did not exit cleanly holds these. Vite is configured with strictPort: true, so it exits rather
than picking another port.
5. Check the certificate
The first Vite run installs a locally trusted development certificate through vite-plugin-mkcert, and it may ask for
your password. Declining leaves Vite unable to serve over HTTPS, which the Shopify preview requires.
Repair
Port already in use
kill $(lsof -t -i :5173)
kill $(lsof -t -i :9292)Then restart. The run-pty dashboard also restarts a single process with enter once its port is free.
Wrong Node version
nvm use
rm -rf node_modules
npm installReinstalling matters because native dependencies are built against the Node version present at install time.
Shopify CLI not authenticated
shopify auth loginThe browser flow has to complete against an account with access to a-sales-affair.
The tunnel never starts
The tunnel waits for port 9292 before launching cloudflared, printing [tunnel] Waiting for Shopify Theme Dev. If the
output stops at that message, the shopify process has not started. Fix that first.
On the first run cloudflared downloads the Cloudflare binary. A proxy or a restricted network blocks this, and the
tunnel process exits.
The preview returns a JSON 400
The tunnel rewrites its origin Host header to 127.0.0.1:9292, because Shopify's local proxy rejects the public
trycloudflare.com hostname. A 400 with a JSON body means that rewrite is not happening.
Restart the tunnel process. If it persists, check scripts/start-cloudflare-tunnel.mjs has not been modified.
Changes to src do not reach the browser
Confirm you are using the cloudflared URL rather than http://127.0.0.1:9292 directly. Modules load from the Vite
server over HTTPS, and a page served over HTTP will not load them.
Confirm the vite process is healthy and reports the file change.
For CSS, confirm the css process is running. PostCSS in watch mode produces the Tailwind output, not Vite, so a stopped css process leaves Tailwind classes stale while TypeScript keeps hot reloading.
Everything starts but the theme looks wrong
reconciliation-strategy = "keep-local" means your local files win over the remote theme. A file you deleted locally
but that still exists on the store will not be restored.
git status --shortUncommitted deletions or local edits explain most of these.
Verify
- All four processes show green in the
run-ptydashboard. - Opening the
cloudflaredURL loads the storefront. - The network panel shows module requests going to
localhost:5173. - Editing a file in
src/entrypoints/updates the browser without a manual reload. - Editing a Tailwind class in a Liquid file updates after the css process rebuilds.
Before you commit
The dev server rewrites snippets/vite-tag.liquid to point at the Vite dev server. Stop the processes and rebuild
before committing:
npm run build
grep -c "5173" snippets/vite-tag.liquidThe count must be 0. Committing the dev-server form of that snippet breaks every bundle on the storefront. See
Assets out of sync.