Skip to content

Development

Starting the dev servers

bash
pnpm dev -- --store my-store.myshopify.com

This command uses concurrently to run two servers in parallel:

ServerWhat it doesURL
shopify theme dev --path themeProxies your Shopify store, serves Liquid-rendered pagesPrinted in terminal (typically http://127.0.0.1:9292)
viteServes frontend assets (JS, CSS) with hot module replacementhttp://localhost:5173

Open the Shopify CLI URL in your browser. You do not need to open the Vite URL directly -- the theme loads assets from it automatically.

TIP

If you have STORE set in your .env file, the Shopify CLI will use it automatically and you can run pnpm dev without the --store flag. Any additional flags after -- are passed through to shopify theme dev.

How the dual-server setup works

The bridge between Shopify and Vite is the vite-tag snippet. In theme/layout/theme.liquid, the layout renders two entry points:

liquid
{%- liquid
  render 'importmap'
  render 'vite-tag', entry: 'theme.css', preload_stylesheet: true
  render 'vite-tag', entry: 'theme.js'
-%}

The vite-tag snippet is auto-generated by vite-plugin-shopify and switches behavior based on environment:

  • Development -- Points <script> and <link> tags to localhost:5173, enabling Vite's HMR client. CSS and JS changes appear instantly without a full page reload.
  • Production -- Points to Shopify CDN asset URLs using the Vite build manifest, serving minified and optimized bundles.

WARNING

Do not edit theme/snippets/vite-tag.liquid or theme/snippets/importmap.liquid manually. They are regenerated by the Vite plugins on every build.

What gets hot-reloaded

File typeBehavior
CSS (theme/frontend/styles/, entrypoints)Instant style injection, no page reload
JavaScript islands (theme/frontend/islands/)HMR via Vite -- component re-imports without full reload
JavaScript libraries (theme/frontend/lib/)HMR where supported, otherwise full reload
Liquid templatesFull page reload triggered by Shopify CLI file sync
Theme settings JSONFull page reload triggered by Shopify CLI file sync

CSS changes are the fastest feedback loop. Liquid changes require the Shopify CLI to sync the file to the store, which takes a few seconds before the page reloads.

Editing workflow

Liquid (sections, blocks, snippets, layouts, templates)

Edit Liquid files in theme/. The Shopify CLI watches for file changes and syncs them to your development store. The browser reloads automatically when the sync completes.

CSS

The main stylesheet entry point is theme/frontend/entrypoints/theme.css, which imports the design token layer (theme/frontend/styles/theme.css) and component styles. Tailwind CSS v4 is processed by the @tailwindcss/vite plugin -- there is no tailwind.config.js file.

Add utility classes directly in Liquid templates. For custom styles, add them to the appropriate CSS layer file in theme/frontend/styles/.

JavaScript islands

Each island is a file in theme/frontend/islands/ that defines a Web Component. The hydration runtime (revive.js) automatically discovers custom elements in the DOM and loads matching island files based on hydration directives:

html
<!-- In a Liquid snippet -->
<quantity-input client:visible>
  <!-- server-rendered content -->
</quantity-input>

When you edit an island file, Vite's HMR re-imports the module. Create new islands by adding a file to theme/frontend/islands/ -- the hydration runtime picks them up automatically via import.meta.glob().

Shared JavaScript

Utility modules live in theme/frontend/lib/. Import them into islands using the @/ path alias:

js
import { debounce } from '@/lib/utils'

Both @/ and ~/ resolve to theme/frontend/.

Common dev tips

Port conflicts -- If port 5173 is in use, Vite automatically picks the next available port and updates the HMR client URL. The vite-tag snippet reads the port from Vite's dev server, so this works transparently.

Multiple stores -- Pass different --store flags to work against different development stores. Each store has its own theme data, so you can test against different configurations:

bash
pnpm dev -- --store staging-store.myshopify.com

Theme editor -- The Shopify theme editor works alongside shopify theme dev. Changes made in the editor are synced back to your local files. Be aware that this can overwrite local edits to JSON template/section files if you edit them simultaneously.

Linting and formatting -- Run these before committing:

bash
pnpm lint       # ESLint
pnpm format     # Prettier (formats Liquid, JS, and CSS)

What's next