Deployment & Production Workflow
Building a great theme means nothing if you can't deploy it safely. This chapter covers the complete deployment pipeline — from testing and debugging to Git workflows, safe deployment strategies, and preparing themes for production.
Time estimate: 45 – 60 minutes
Tags:
CLI
Workflow
Pre-Deployment Testing Checklist
Before pushing any theme to production, run through this comprehensive checklist. Professional developers never deploy without testing:
PRE-DEPLOYMENT TESTING CHECKLIST
═══════════════════════════════════════════
PAGES TO TEST
□ Homepage (with all sections populated)
□ Collection page (with products)
□ Collection page (empty collection)
□ Product page (with variants)
□ Product page (single variant)
□ Product page (sold out)
□ Product page (on sale)
□ Cart page (with items)
□ Cart page (empty)
□ Search page (with results)
□ Search page (no results)
□ Blog page
□ Article page
□ Custom page (e.g., About Us)
□ Contact page
□ 404 error page
□ Password page
□ Gift card page
□ Customer login page
□ Customer account page
FUNCTIONALITY
□ Add to cart works (all product types)
□ Cart updates quantity correctly
□ Cart removes items
□ Navigation links all work (no broken links)
□ Search returns relevant results
□ Predictive search works (if implemented)
□ Mobile menu opens and closes
□ All forms submit correctly
□ Variant selector updates price and image
□ Newsletter signup submits
□ Social media links open in new tabs
RESPONSIVE DESIGN
□ Test at 320px (smallest phone)
□ Test at 375px (standard phone)
□ Test at 768px (tablet portrait)
□ Test at 1024px (tablet landscape)
□ Test at 1440px (desktop)
□ No horizontal scrollbar at any width
□ All text is readable (no overflow)
□ Buttons/links are tappable (44px min)
□ Images don't overflow containers
BROWSER TESTING
□ Chrome (latest)
□ Firefox (latest)
□ Safari (latest — test on Mac/iPhone if possible)
□ Edge (latest)
□ Mobile Safari (iOS)
□ Mobile Chrome (Android)
PERFORMANCE
□ Lighthouse score above 50 (ideally 70+)
□ No render-blocking resources
□ Images optimized with srcset
□ Lazy loading implemented
□ No console errors
ACCESSIBILITY
□ Skip-to-content link works
□ All images have alt text
□ Color contrast meets WCAG AA
□ Keyboard navigation works (Tab through page)
□ Focus states are visible
□ Form labels are properly associated
□ ARIA labels on interactive elements
SEO
□ Page titles are unique and descriptive
□ Meta descriptions present
□ Canonical URLs are correct
□ Open Graph tags present
□ Structured data (if implemented)
□ No broken links
Debugging Shopify Themes
Debugging Liquid Errors
When Liquid has errors, the Shopify CLI terminal shows them. Common patterns:
ERROR: "Liquid error: Unknown tag 'endfor'"
FIX: Check for typos — ensure {% endfor %} matches {% for %}
Check nesting — every if/for/case needs a closing tag
ERROR: "Liquid error: undefined variable"
FIX: Variable doesn't exist in current scope.
If using {% render %}, pass the variable explicitly.
Check for typos in variable names.
ERROR: "Liquid error: Array index out of bounds"
FIX: Check array .size before accessing by index.
Use {% if array.size > 0 %} before looping.
ERROR: "Liquid error: wrong number of arguments"
FIX: Check filter syntax. Common mistake:
❌ {{ image | image_url: 400 }}
✅ {{ image | image_url: width: 400 }}
ERROR: Page renders but section is blank
FIX: 1. Check {% if %} conditions — something is probably blank/nil
2. Output debug: {{ section.settings | json }}
3. Check schema — setting IDs must match Liquid references
4. Check template JSON — is the section referenced?
Browser DevTools Debugging
| Issue | DevTools Tool | How to Use |
|---|---|---|
| CSS not applying | Elements panel → Styles | Inspect the element. Check if your CSS is loaded. Look for overriding rules (crossed out). |
| Layout broken | Elements panel → Layout | Enable Grid/Flexbox overlays to visualize layout structure. |
| JavaScript errors | Console tab | Look for red errors. Click the file:line link to see the source. |
| Network issues | Network tab | Check for 404s (missing files), slow resources, large downloads. |
| Performance issues | Lighthouse tab | Run Performance audit. Read opportunities and diagnostics. |
| Mobile rendering | Device toolbar (Ctrl+Shift+M) | Toggle device mode. Select specific devices or set custom dimensions. |
| Accessibility issues | Lighthouse → Accessibility | Run Accessibility audit. Also use Elements → Accessibility panel for individual elements. |
Theme Editor Debugging
PROBLEM: Section doesn't appear in "Add section" menu
CHECK: Does your schema have a "presets" array?
Without presets, the section can't be added manually.
PROBLEM: Settings don't appear in theme editor sidebar
CHECK: Is the setting inside the "settings" array in schema?
Is the JSON valid? (missing comma, bracket, quote)
Validate JSON at jsonlint.com
PROBLEM: Blocks can't be clicked in the editor preview
CHECK: Is {{ block.shopify_attributes }} on the block wrapper?
This is REQUIRED for editor interactivity.
PROBLEM: Section shows in editor but not on live site
CHECK: Is the section in the JSON template's "order" array?
Is there a conditional that hides it?
PROBLEM: Schema changes not reflecting
FIX: Save the section file, refresh the theme editor.
Sometimes you need to close and reopen the editor.
Clear browser cache if needed.
Deployment Strategies
Strategy 1: Push to Unpublished Theme (Safest)
This is the recommended approach for client stores. Push your changes to a new unpublished theme, let the client preview and approve it, then publish.
# Step 1: Push to a new unpublished theme
shopify theme push --unpublished \
--store client-store.myshopify.com
# This creates a new theme named "[development] Your Theme"
# It does NOT affect the live store
# Step 2: Share preview link with client
# The CLI will output a preview URL like:
# https://client-store.myshopify.com/?preview_theme_id=XXXXXXX
# Step 3: After client approves, publish via Shopify Admin
# Online Store → Themes → Actions → Publish
# Or publish via CLI (use with caution):
shopify theme publish --theme THEME_ID \
--store client-store.myshopify.com
Strategy 2: Push to Existing Theme
Use this when updating an existing unpublished theme during development:
# List existing themes to find the ID
shopify theme list --store client-store.myshopify.com
# Output:
# ID NAME ROLE
# 123456789 Dawn (Live) live
# 987654321 My Custom Theme unpublished
# Push to the specific unpublished theme
shopify theme push --theme 987654321 \
--store client-store.myshopify.com
Strategy 3: Push to Live Theme (Risky)
Pushing directly to the live theme affects the store immediately. Customers will see changes in real-time. Only do this for small, well-tested changes — never for major updates.
# This pushes directly to the live published theme
# WARNING: Changes are immediately visible to customers
shopify theme push --allow-live \
--store client-store.myshopify.com
# SAFER: Push specific files only
shopify theme push --allow-live \
--only sections/header.liquid \
--only assets/section-header.css \
--store client-store.myshopify.com
Ignoring Files During Push
# Never overwrite the merchant's customized settings
shopify theme push \
--ignore config/settings_data.json \
--store client-store.myshopify.com
# You can also create a .shopifyignore file
# in your project root:
# .shopifyignore
config/settings_data.json
templates/*.json
Create a .shopifyignore file in your project root. It works like
.gitignore but for Shopify CLI. Any files listed here won't be
pushed or pulled. This protects merchant settings and template configurations
from being overwritten.
# Don't overwrite merchant's theme settings
config/settings_data.json
# Don't overwrite template configurations
# (merchant may have added/reordered sections)
templates/*.json
# Keep the default templates in your repo
# but don't push them over merchant customizations
!templates/product.json
!templates/collection.json
Git Workflow for Production
Professional Branching Model
RECOMMENDED BRANCHING MODEL
═══════════════════════════════════════════
main (or production)
│
├── The stable, production-ready code
├── Only merged from staging or hotfix branches
├── Tagged with version numbers (v1.0.0, v1.1.0)
│
└── staging (or develop)
│
├── Integration branch for testing
├── Features merge here first
├── Pushed to unpublished theme for review
│
├── feature/hero-redesign
│ └── New feature development
│
├── feature/mega-menu
│ └── Another feature in parallel
│
└── fix/mobile-nav-bug
└── Bug fix branch
SIMPLIFIED MODEL (for solo developers):
main
│
├── Stable theme code
│
├── feature/new-section
│ └── Develop → Test → Merge to main
│
└── fix/cart-bug
└── Fix → Test → Merge to main
Complete Git Deployment Workflow
# ── DEVELOPMENT PHASE ──────────────────────────
# 1. Create a feature branch
git checkout main
git pull origin main
git checkout -b feature/announcement-bar
# 2. Develop with live preview
shopify theme dev --store dev-store.myshopify.com
# 3. Make changes, test, commit regularly
git add sections/announcement-bar.liquid
git add assets/section-announcement-bar.css
git commit -m "feat: add announcement bar section with auto-rotate"
git add sections/announcement-bar.liquid
git commit -m "fix: announcement bar dismiss uses sessionStorage"
# 4. Push branch to GitHub
git push -u origin feature/announcement-bar
# ── REVIEW PHASE ──────────────────────────────
# 5. Merge to main when feature is complete
git checkout main
git merge feature/announcement-bar
git push origin main
# 6. Clean up feature branch
git branch -d feature/announcement-bar
git push origin --delete feature/announcement-bar
# ── DEPLOYMENT PHASE ──────────────────────────
# 7. Push to unpublished theme on client store
shopify theme push --unpublished \
--ignore config/settings_data.json \
--store client-store.myshopify.com
# 8. Share preview link with client for approval
# 9. After approval, publish the theme
# (via Shopify Admin or CLI)
# 10. Tag the release in Git
git tag -a v1.2.0 -m "Add announcement bar section"
git push origin v1.2.0
Version Tagging
Use semantic versioning to tag releases:
| Version | When to Bump | Example |
|---|---|---|
| Major (X.0.0) | Complete theme redesign, breaking changes | v1.0.0 → v2.0.0 |
| Minor (0.X.0) | New sections, new features, non-breaking | v1.0.0 → v1.1.0 |
| Patch (0.0.X) | Bug fixes, small adjustments | v1.1.0 → v1.1.1 |
# Create an annotated tag
git tag -a v1.0.0 -m "Initial theme release"
# Push tags to GitHub
git push origin v1.0.0
# Push all tags
git push origin --tags
# List all tags
git tag -l
# View tag details
git show v1.0.0
Syncing Theme Editor Changes
One of the trickiest aspects of Shopify development: merchants make changes
through the theme editor, which modifies config/settings_data.json
and template JSON files. You need to sync these changes with your local codebase.
Commit Your Local Changes First
git add .
git commit -m "feat: my latest local changes"
Pull Theme Editor Changes
# Pull only settings and templates (what the editor changes)
shopify theme pull \
--only config/settings_data.json \
--only "templates/*.json" \
--store client-store.myshopify.com
Review and Commit
# Review what changed
git diff
# Commit the editor changes
git add config/settings_data.json templates/
git commit -m "sync: pull theme editor changes from client"
Establish a rule with clients: "Don't make theme editor changes while I'm actively developing." Simultaneous local development and theme editor changes create conflicts. Set specific times for development work and merchant customization to avoid this.
Backup Strategies
# Before ANY major deployment, create a backup:
# Option 1: Download the live theme as a backup
shopify theme pull \
--theme LIVE_THEME_ID \
--path ./backups/backup-$(date +%Y%m%d) \
--store client-store.myshopify.com
# Option 2: Duplicate the live theme in Shopify Admin
# Online Store → Themes → Actions → Duplicate
# This creates a copy the merchant can revert to
# Option 3: Git tags serve as backups
git tag -a backup/pre-v2-launch -m "Backup before v2 launch"
git push origin backup/pre-v2-launch
Before publishing a new theme version on a live store, always duplicate the current live theme in Shopify Admin. If anything goes wrong, the merchant can instantly revert by publishing the duplicate. This takes 10 seconds and can save hours of crisis management.
Rollback Procedures
When something goes wrong in production, you need to act fast:
Instant Rollback via Shopify Admin
Go to Online Store → Themes
Find the backup/duplicate theme you created before deployment.
Click Actions → Publish
This instantly makes the old theme live again. The new theme becomes unpublished.
Debug the New Theme
Fix the issues on the now-unpublished new theme. Test thoroughly. Then publish again.
Rollback via Git
# Option 1: Revert a specific commit
git revert HEAD # Reverts the last commit
git push
# Option 2: Reset to a specific tag
git checkout v1.1.0 # Go to a tagged version
shopify theme push --unpublished \
--store client-store.myshopify.com
# Option 3: Reset branch to a previous state (destructive!)
git reset --hard v1.1.0
git push --force # CAUTION: rewrites remote history
Production Readiness Checklist
PRODUCTION READINESS
═══════════════════════════════════════════
CODE QUALITY
□ All debug output removed ({{ product | json }}, HTML comments)
□ No console.log() statements in JavaScript
□ No TODO or FIXME comments left unresolved
□ Code is consistently formatted
□ Snippets are documented with accepted parameters
□ Schema settings have helpful labels, info text, and defaults
□ Translation keys used for all user-facing strings
THEME SETTINGS
□ settings_schema.json has theme_info block (name, version, author)
□ All global settings have sensible defaults
□ Color settings provide good default palette
□ Typography defaults are readable and professional
CONTENT
□ All sections render placeholder content when no data is set
□ Empty states are handled gracefully (empty cart, no results, etc.)
□ All images have meaningful alt text
□ Locales file has all required translation keys
LEGAL
□ No copyrighted code from premium themes
□ No copyrighted images or fonts
□ License information is clear (if distributing)
□ Privacy-related features comply with GDPR (cookie consent, etc.)
DEPLOYMENT
□ .shopifyignore is configured
□ .gitignore is configured
□ Git repository is clean (no uncommitted changes)
□ Live theme is backed up (duplicated in Shopify Admin)
□ Client has been notified of deployment timing
□ Post-deployment verification plan is ready
Post-Deployment Verification
After deploying, perform a quick verification:
IMMEDIATELY AFTER PUBLISHING
═══════════════════════════════════════════
□ Visit the homepage — does it load correctly?
□ Visit a product page — can you add to cart?
□ Visit a collection page — do products display?
□ Test on mobile (real phone, not just DevTools)
□ Complete a test checkout (on dev store) or verify
checkout loads correctly (on live store)
□ Check browser console for JavaScript errors
□ Run a quick Lighthouse audit
□ Verify header and footer render correctly
□ Check that merchant's custom content is intact
□ Notify the client that deployment is complete
Automated Deployment Concepts
As you grow, consider automating deployments with GitHub Actions. Here's a basic concept:
# This is a conceptual example — adapt to your needs
name: Deploy Shopify Theme
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Shopify CLI
run: npm install -g @shopify/cli @shopify/theme
- name: Deploy to Shopify
env:
SHOPIFY_CLI_THEME_TOKEN: ${{ secrets.SHOPIFY_CLI_THEME_TOKEN }}
SHOPIFY_FLAG_STORE: ${{ secrets.SHOPIFY_STORE }}
run: |
shopify theme push \
--theme ${{ secrets.THEME_ID }} \
--ignore config/settings_data.json
CI/CD is powerful but adds complexity. As a beginner, focus on mastering the manual deployment workflow first. Once you're confident and handling multiple client stores, then set up automation. Premature automation creates more problems than it solves.
Key Takeaways
- Always run the pre-deployment testing checklist before pushing to production
- Use
--unpublishedflag for safe deployments to client stores - Protect merchant settings with
.shopifyignoreand--ignoreflags - Never push directly to live themes without a backup
- Duplicate the live theme in Shopify Admin before every major deployment
- Use Git tags for version tracking and easy rollbacks
- Coordinate with clients to avoid simultaneous theme editor and code changes
- Sync theme editor changes with
shopify theme pull --only - Perform post-deployment verification immediately after publishing
- Master manual deployment before setting up CI/CD automation