Develop, Preview and Publish Shopify Themes Safely with Shopify CLI
A practical Shopify CLI workflow: pull a local theme copy, preview with hot reload, validate with Theme Check, and publish without breaking the live store.
Why edit themes locally at all
The theme editor in the Shopify admin is a good tool for changing settings, but it is a poor place to write Liquid. Editing code inside a browser textarea gives you no diff view, no revert discipline beyond the theme’s version history, and no way to review changes before they exist on the store. Anyone who has fixed a broken {% for %} loop in a section file knows how unforgiving that environment is when the page stops rendering.
Shopify CLI inverts the workflow. Your theme lives as ordinary files on your machine, you edit them with real tooling, and every command that touches the store is explicit. This guide walks through the complete cycle: getting a local copy, previewing changes with hot reload, validating them, and pushing to the store without ever overwriting the live theme by accident.
Set up once: Node.js and the CLI
Shopify CLI is distributed as an npm package and runs on Node.js. Install the current version globally:
npm install -g @shopify/cli@latest
Then authenticate against your store:
shopify auth login --store example.myshopify.com
The store flag accepts either the store prefix (example) or the full myshopify.com URL. Use a staff account or a theme-appropriate permission set; you do not need full admin rights to work on themes, and limiting the token’s scope limits what a mistake can do.
Verify the installation with shopify version and shopify theme info, which reports the store the CLI is currently pointed at. Pointing commands at the wrong store is one of the most common ways otherwise careful people push a client’s theme to the wrong shop.
Get a local copy with theme pull
Before changing anything, create a faithful local copy of the theme you intend to edit:
shopify theme pull --store example.myshopify.com
Run interactively, the command asks which theme to pull. Pull the live theme only as a reference copy; if you are doing development work, pulling a duplicate of the live theme is the safer base. The download produces the standard theme directory structure — assets, config, layout, locales, sections, snippets and templates — which is also the structure the theme dev command requires.
Two things are worth checking once the pull completes. First, confirm that .gitignore excludes nothing essential if you are putting the theme under version control, and commit the pristine pulled state before your first edit so you always have a clean diff. Second, look for configuration files that were never meant to leave the store, such as leftover app embeds from uninstalled apps — the residue cleanup process is worth running while you are already in the files, as covered in our guide to removing leftover app code from Shopify themes.
Preview with theme dev, not with your eyes closed
The core of the local workflow is the dev server:
shopify theme dev --store example.myshopify.com
The command uploads your current theme to the store as a development theme and gives you three things: a local preview URL at http://127.0.0.1:9292 that reflects file changes as you save them, a link to the theme editor in the admin, and a shareable preview link for other people on the team. Hot reload is the default behaviour, updating CSS and sections without full page reloads; use --live-reload full-page when you want the whole page to refresh on every change, or --live-reload off when you are debugging something that reload itself would destroy.
Development themes have limits you should plan around:
- They are temporary. Development themes are deleted when you run
shopify auth logout, so preview links break. If a stakeholder needs a link that survives your session, useshopify theme shareto upload the theme as a new unpublished theme instead. - They are replaced, not merged. If a development theme already exists for your environment, running
theme devagain replaces it with your local theme. That is convenient, but it means anything edited directly in the development theme through the admin is lost. - Checkout is not previewable locally. The local URL cannot preview checkout customizations. Test those on an unpublished theme pushed to the store.
- Editor changes do not sync back by default. If someone changes theme settings through the admin while you develop locally, pass
--theme-editor-syncand pick a--reconciliation-strategy—keep-local,keep-remoteorabort— so JSON settings conflicts are resolved deliberately instead of silently.
Validate before every push: theme check
Every push to the store should pass static analysis first:
shopify theme check
Theme Check parses your Liquid and flags both errors and best-practice suggestions. Treat errors as blockers: undefined objects, invalid schema in sections, unreachable code. Suggestions — unused variables, accessible markup hints, performance patterns — are worth reading rather than suppressing, because the same patterns that slow a template also tend to hide bugs.
If you run pushes from CI, add the --strict flag to shopify theme push so that a failing Theme Check blocks the upload. The theme performance guide goes deeper into the rendering patterns Theme Check warns about; see our article on diagnosing Shopify theme performance issues for the profiling side of the picture.
Push without destroying anything
shopify theme push uploads your local files and overwrites the remote version of the theme you target. Every flag exists to narrow that blast radius, and the safe patterns all follow from understanding which theme you are writing to.
Push to a new unpublished theme first. The default safe target:
shopify theme push --unpublished
This creates a fresh unpublished theme in the store’s theme library and pushes to it. Nothing customer-facing changes. Use --theme "Working name" to give the new theme a recognizable name — after a few rounds of iteration, “Copy of Copy of Dawn 2” libraries are their own kind of incident.
Never let the push delete files implicitly. By default, files that exist on the remote theme but not in your local directory are deleted. If your local copy is partial — you pulled with --only, or you are working from a repo that omits generated files — add:
shopify theme push --unpublished --nodelete
Push only what changed. For surgical changes, --only and --ignore accept file paths and quoted wildcards and can be used multiple times. Pushing one section file you just reviewed is a smaller operation to reason about than pushing the whole theme.
Treat the live theme as a deliberate act. Pushing to the live theme requires --allow-live, and the flag is mandatory rather than optional in non-interactive environments. That friction is intentional: the live theme is what customers see, and theme push --live --allow-live makes changes visible immediately with no separate review step. The one defensible routine use is a hotfix to a broken template when every minute counts — and even then, an unpublished theme plus theme publish is usually only seconds slower and leaves a reviewable artifact.
Publish deliberately
When the unpublished theme has passed review, make it live:
shopify theme publish --theme <theme-id>
Find the theme ID with shopify theme list, which shows each theme’s ID and status. Before publishing, walk the templates that actually carry your revenue: home page, a product page, a collection page, cart, and checkout if you touched anything that renders there. Check them on a phone viewport, not just a desktop browser, since most storefront traffic is mobile and section layout breakage shows up first on narrow widths.
Confirm afterwards with shopify theme list that the expected theme is live, and keep the previous live theme in the library for a quick rollback rather than deleting it immediately. Publishing is reversible only if you have not destroyed the thing you would revert to.
Non-interactive environments need explicit targets
In CI or scripts there is no prompt to ask which theme you meant, so the CLI refuses to guess. A push in a non-interactive environment must specify its target with one of --development, --live, --theme or --unpublished, and targeting the live theme additionally requires --allow-live. This is a good design to lean into: a pipeline that cannot accidentally publish to production is a pipeline you can trust with a Friday deploy.
When the workflow is not the bottleneck
The CLI removes the mechanical risk from theme work, but it cannot fix a theme that has grown unmanageable — nested snippet chains, settings conflicts, or an Online Store 1.0 codebase still waiting for a structural upgrade. If you are weighing a rebuild against continued patching, our comparison of page builders vs custom themes covers the trade-offs, and the guide to migrating vintage themes to Online Store 2.0 describes what that structural upgrade involves. For stores that need hands-on work, our Shopify development service runs this exact workflow — local development, checked pushes, deliberate publishes — and the Shopify platform page outlines what we maintain on that stack generally.
Official sources.
Use these references to verify platform-specific behavior and version details.
Continue with the surrounding work.
How to Diagnose and Fix Shopify Theme Performance Issues
How to Remove Leftover App Code From a Shopify Theme
Broader context from the YCTheme blog.
Page Builders vs Custom Themes: When Each Approach Pays Off
Why the choice between page builders and custom themes is really a decision about who edits the site, how often, and at what performance budget.
Staging Environments: How Professional Teams Ship CMS Changes Without Breaking Production
Staging is where risky changes prove themselves before customers see them. A practical look at how WordPress, Joomla, TYPO3 and Shopify teams stage, test and promote changes.