Shopify CLI Integration and Hot Reload Workflow
Connect your React build process with Shopify CLI for a seamless development experience. Run both tools together with the --path flag pointing to your shopify-theme folder.
Now that we have Vite (or Webpack) building our React code directly to shopify-theme/assets/, we need to connect it with Shopify CLI. The key is telling CLI to only sync the shopify-theme/ folder—not our entire project.
The Development Flow
Here’s what we want to achieve:
┌──────────────────────────────────────────────────────────────┐│ YOUR LOCAL MACHINE ││ ││ ┌─────────────┐ ┌──────────────────────────────────┐ ││ │ Edit React │ │ Vite │ ││ │ src/*.tsx │ ────▶ │ Watches src/ │ ││ └─────────────┘ │ Outputs to shopify-theme/assets │ ││ └──────────────────────────────────┘ ││ │ ││ ▼ ││ ┌─────────────┐ ┌──────────────────────────────────┐ ││ │ Edit Liquid │ │ Shopify CLI │ ││ │ shopify- │ ────▶ │ Watches shopify-theme/ │ ││ │ theme/* │ │ Syncs ONLY that folder │ ││ └─────────────┘ └──────────────────────────────────┘ ││ │ │└────────────────────────────────────────│─────────────────────┘ │ ▼ ┌───────────────────────────────┐ │ Development Store │ │ yourstore.myshopify.com │ └───────────────────────────────┘ │ ▼ ┌───────────────────────────────┐ │ Browser Auto-Refresh │ │ See changes instantly │ └───────────────────────────────┘Prerequisites
Install Shopify CLI if you haven’t:
# macOS/Linuxbrew tap shopify/shopifybrew install shopify-cli
# Or with npm (all platforms)npm install -g @shopify/cli @shopify/themeVerify installation:
shopify version# Should output: 3.x.x or higherStep 1: Authenticate with Shopify
Log in to your Shopify Partner or store account:
shopify auth loginThis opens a browser for authentication. Once complete, you’re ready to connect to your development store.
Step 2: The Key Flag: --path
Since our Shopify theme lives in a subfolder, we must tell CLI where it is:
# Point CLI to the shopify-theme foldershopify theme dev --path shopify-theme --store your-store.myshopify.comThis is crucial. Without --path, CLI would try to sync your entire project (including node_modules, src/, etc.) which would fail.
Step 3: Running Both Tools Together
You need two processes running simultaneously:
- Vite watching
src/→ building directly toshopify-theme/assets/ - Shopify CLI watching
shopify-theme/→ syncing to your store
Option A: Two Terminal Windows
The simplest approach—open two terminals:
Terminal 1: Vite
npm run devTerminal 2: Shopify CLI
shopify theme dev --path shopify-theme --store your-store.myshopify.comOption B: Concurrently (Recommended)
Use concurrently to run both in a single terminal:
npm install -D concurrentlyUpdate package.json:
{ "scripts": { "dev": "vite build --watch --mode development", "theme": "shopify theme dev --path shopify-theme --store your-store.myshopify.com", "start": "concurrently \"npm:dev\" \"npm:theme\"", "build": "tsc --noEmit && vite build", "push": "npm run build && shopify theme push --path shopify-theme" }}What each script does:
dev: Vite watchessrc/and rebuilds toshopify-theme/assets/on changestheme: Shopify CLI watchesshopify-theme/and syncs to your dev storestart: Runs both together—this is your main development commandbuild: Typecheck first, then build optimized production bundlepush: Build then deploy to Shopify
Now run everything with:
npm startOutput shows both processes:
[dev] vite v5.0.0 building for development...[theme] ✓ Theme dev server running at http://127.0.0.1:9292[dev] ✓ built in 234ms[dev] shopify-theme/assets/react-bundle.js 45.12 kB[theme] Syncing theme #123456789...[dev] watching for file changes...Option C: npm-run-all (Alternative)
Another popular option:
npm install -D npm-run-all{ "scripts": { "dev": "vite build --watch", "theme": "shopify theme dev --path shopify-theme", "start": "run-p dev theme" }}Step 4: Configure Shopify CLI
Create a shopify.theme.toml configuration file in your project root:
[environments.development]store = "your-store.myshopify.com"path = "shopify-theme"# theme = "123456789" # Optional: pin to specific theme ID
[environments.staging]store = "your-store.myshopify.com"path = "shopify-theme"theme = "987654321"
[environments.production]store = "your-store.myshopify.com"path = "shopify-theme"theme = "111222333"Now you can run without flags:
# Uses development environment by defaultshopify theme dev
# Or specify environmentshopify theme dev --environment stagingUpdate your npm scripts to use environments:
{ "scripts": { "theme": "shopify theme dev", "theme:staging": "shopify theme dev --environment staging", "start": "concurrently \"npm:dev\" \"npm:theme\"" }}Step 5: No Ignore List Needed!
Because we’re only syncing shopify-theme/, we don’t need complex ignore patterns. The folder contains only deployable files:
shopify-theme/├── assets/ # ✓ Synced (includes React bundle)├── config/ # ✓ Synced├── layout/ # ✓ Synced├── locales/ # ✓ Synced├── sections/ # ✓ Synced├── snippets/ # ✓ Synced└── templates/ # ✓ Synced
# These are OUTSIDE shopify-theme/ and never synced:src/ # React sourcenode_modules/ # DependenciesIf you do need ignores (e.g., for local testing files), add them to the config:
[environments.development]path = "shopify-theme"ignore = [ "assets/*.map", # Skip source maps "**/.DS_Store" # Skip macOS files]Step 6: Environment-Specific Configuration
Create environment files for different contexts:
VITE_DEBUG=trueVITE_API_URL=https://your-store.myshopify.com
# .env.productionVITE_DEBUG=falseVITE_API_URL=https://your-store.myshopify.comAccess in React:
const isDebug = import.meta.env.VITE_DEBUG === 'true';const apiUrl = import.meta.env.VITE_API_URL;Step 7: Browser Sync and Auto-Refresh
Shopify CLI provides automatic browser refresh when files change. The flow:
- Edit a React file → Vite rebuilds to
shopify-theme/assets/ - Shopify CLI detects the change → Syncs to store → Triggers browser refresh
Hot Reloading Caveat
Unlike a standard React dev server, we can’t do true HMR (Hot Module Replacement) because:
- React runs inside Shopify’s hosted page
- Shopify CLI does full page refreshes
The refresh is still fast (1-2 seconds), but React state resets on each change. Mitigate this by:
- Using URL-based state where possible
- Persisting dev state to localStorage
- Using React DevTools for state inspection
/* * Persist state across page refreshes during development * Since Shopify CLI does full page refreshes (not HMR), state resets on every change. * This middleware saves state to localStorage so it survives refreshes. */import { create } from 'zustand';import { persist } from 'zustand/middleware';
const useCart = create( persist( (set) => ({ items: [], // ... actions }), { name: 'cart-storage', // localStorage key // State is automatically saved on changes and restored on page load } ));Step 8: Debugging Tips
View Console Logs
Open browser DevTools to see your React logs:
if (import.meta.env.DEV) { console.log('🚀 React bundle loaded'); console.log('Environment:', import.meta.env.MODE);}Inspect Network Requests
Watch the Network tab for:
react-bundle.jsloading successfully- API calls to
/cart/add.js,/cart.js, etc. - Any 404 errors for missing assets
React DevTools
Install the React DevTools browser extension:
This lets you inspect component trees and state even on your Shopify dev store.
Source Maps
Ensure source maps are enabled for debugging:
export default defineConfig({ build: { sourcemap: true, },});In DevTools, you’ll see your original .tsx files instead of bundled code.
Common Workflow Issues
”Path not found” or theme not syncing
Verify the path is correct:
# Check the folder existsls shopify-theme/
# Test CLI can find itshopify theme list --path shopify-theme“Store not found”
Ensure you’re authenticated and have access:
shopify auth loginshopify theme list --store your-store.myshopify.comBundle not updating in browser
- Verify Vite is running and watching
- Check Shopify CLI is syncing (look for “Syncing…” messages)
- Hard refresh:
Cmd+Shift+R(Mac) orCtrl+Shift+R(Windows)
“Port already in use”
If Shopify CLI can’t start:
# Find what's using the portlsof -i :9292
# Use a different portshopify theme dev --path shopify-theme --port 9293TypeScript errors not showing
Run typecheck separately:
npm run typecheckOr add it to your start script:
{ "scripts": { "start": "concurrently \"npm:dev\" \"npm:theme\" \"npm:typecheck:watch\"", "typecheck:watch": "tsc --noEmit --watch" }}Complete Development Workflow
Here’s the full workflow you’ll use daily:
# 1. Start development (Vite + Shopify CLI)npm start
# 2. Open the preview URL (shown in terminal)# Usually http://127.0.0.1:9292
# 3. Edit files:# - React: src/components/*.tsx → Vite builds → Syncs automatically# - Liquid: shopify-theme/sections/*.liquid → Syncs directly
# 4. View changes in browser (auto-refreshes)
# 5. When done, Ctrl+C to stop both processesProduction Deployment
For production, build once and push:
# Build production bundle (minified, no console.log)npm run build
# Push entire theme to productionshopify theme push --path shopify-theme --environment productionOr use the combined script:
npm run push # Runs build then pushComplete Package.json
Here’s the complete package.json with all scripts:
{ "name": "shopify-react-theme", "private": true, "type": "module", "scripts": { "dev": "vite build --watch --mode development", "build": "tsc --noEmit && vite build", "theme": "shopify theme dev --path shopify-theme", "theme:staging": "shopify theme dev --path shopify-theme --environment staging", "start": "concurrently \"npm:dev\" \"npm:theme\"", "typecheck": "tsc --noEmit", "typecheck:watch": "tsc --noEmit --watch", "push": "npm run build && shopify theme push --path shopify-theme", "push:staging": "npm run build && shopify theme push --path shopify-theme --environment staging", "push:production": "npm run build && shopify theme push --path shopify-theme --environment production" }, "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", "zustand": "^4.4.0" }, "devDependencies": { "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "@vitejs/plugin-react": "^4.2.0", "concurrently": "^8.2.0", "typescript": "^5.3.0", "vite": "^5.0.0" }}Key Takeaways
- Use
--path shopify-themeto tell CLI where your theme folder is - Run Vite and CLI together with
concurrentlyfor single-command startup - No complex ignore lists needed—the folder structure handles separation
- Configure environments in
shopify.theme.tomlfor dev/staging/production npm startis your single command for the complete dev workflow
Your development environment is now complete! In the next module, we’ll build the bridge that passes data from Liquid to React.
Finished this lesson?
Mark it complete to track your progress.
Discussion
Loading comments...