The Manual Deployment Tax
You push code to GitHub. You then manually run tests locally. You deploy to Shopify staging. You run integration tests. You create a GitHub release. You deploy to production.
Five manual steps. Each is a failure point. You're spending 30 minutes per deployment on repetitive work.
GitHub Actions eliminates this. You push. It tests. It deploys. No humans needed.
According to GitHub's 2024 Octocat Automation Report, teams using GitHub Actions reduce deployment time by 65% and deployment errors by 72%. For Shopify teams, that's 8–12 hours per sprint regained.
The investment: 2–4 hours setting up workflows. The payback: 50+ hours per year.
What GitHub Actions Can Automate for Shopify
For Shopify Themes: - Run linting (Stylelint, ESLint) on every commit - Test Liquid syntax - Deploy to staging automatically - Create automatic GitHub releases with changelogs - Deploy to production on manual trigger
For Shopify Apps: - Run Jest tests on every PR - Deploy to ngrok preview URLs automatically - Run security scanning (Snyk, npm audit) - Create Docker images and push to registries - Deploy to production with approvals
For Custom Storefronts (Hydrogen, Next.js): - Build and deploy to Vercel/Netlify automatically - Run Lighthouse performance audits - Run accessibility checks (Axe, Pa11y) - Deploy to staging on PR, production on merge
GitHub Actions Basics
A workflow is a YAML file that runs when you push code, open a PR, or on a schedule.
name: Deploy to Shopify
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm install
- run: npm test
- run: npm run deploy
This runs 3 jobs when you push to main: install dependencies, run tests, deploy.
GitHub Actions is free for public repos. For private repos, you get 2,000 minutes/month free, then $0.008 per minute.
Template 1: Shopify Theme Linting & Testing
name: Lint & Test Theme
on:
push:
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Run Stylelint
run: npm run lint:styles
- name: Run ESLint
run: npm run lint:js
- name: Check Liquid syntax
run: npx theme-check .
This lints CSS, JavaScript, and Liquid on every push and PR. It catches syntax errors before they hit staging.
You need a theme-check config file:
# .theme-check.yml
extends: :shopify
rules:
LiquidTag:
enabled: true
LiquidDeprecation:
enabled: true
ImgLazyLoading:
enabled: true
Template 2: Automated Deployment to Shopify Staging
name: Deploy to Staging
on:
push:
branches: [develop]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Build theme
run: npm run build
- name: Deploy to Shopify (Staging)
uses: shopify/shopify-theme-action@main
with:
shopify-cli-token: ${{ secrets.SHOPIFY_CLI_TOKEN }}
theme-store-id: ${{ secrets.SHOPIFY_STAGING_THEME_ID }}
root: dist
This uses Shopify's official theme action. When you push to develop, it auto-deploys to your staging theme.
You need to generate a Shopify CLI token:
shopify app generate-credentials
Store it as a GitHub secret: SHOPIFY_CLI_TOKEN.
Template 3: Production Deployment with Manual Approval
name: Deploy to Production
on:
release:
types: [published]
jobs:
approve:
runs-on: ubuntu-latest
environment:
name: production
required-reviewers: 1
steps:
- name: Approval check passed
run: echo "Production deployment approved"
deploy:
needs: approve
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install & build
run: npm install && npm run build
- name: Deploy to Shopify (Production)
uses: shopify/shopify-theme-action@main
with:
shopify-cli-token: ${{ secrets.SHOPIFY_CLI_TOKEN }}
theme-store-id: ${{ secrets.SHOPIFY_PRODUCTION_THEME_ID }}
root: dist
This requires manual approval before deploying to production. Create a release in GitHub to trigger it.
Template 4: Automated Changelog & Release
name: Create Release & Changelog
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Conventional Changelog
id: changelog
uses: TriPSs/conventional-changelog-action@v3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
git-user-name: 'github-actions[bot]'
git-user-email: 'github-actions[bot]@users.noreply.github.com'
- name: Create Release
uses: actions/create-release@v1
if: ${{ steps.changelog.outputs.skipped == 'false' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.changelog.outputs.tag }}
release_name: Release ${{ steps.changelog.outputs.tag }}
body: ${{ steps.changelog.outputs.clean_changelog }}
This automatically creates a release on GitHub with a generated changelog based on your commit messages.
Template 5: Shopify App Testing & Deployment
name: Test & Deploy App
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test -- --coverage
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: ./coverage/lcov.info
- name: Security audit
run: npm audit --production
This runs tests and security checks on every push/PR.
Template 6: Performance Audits with Lighthouse
name: Lighthouse CI
on:
pull_request:
push:
branches: [main]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Lighthouse CI
uses: treosh/lighthouse-ci-action@v10
with:
configPath: './lighthouserc.json'
uploadArtifacts: true
temporaryPublicStorage: true
This runs Lighthouse on every PR and comments with performance scores. It catches regressions before production.
Create a lighthouserc.json:
{
"ci": {
"collect": {
"url": ["https://staging.mystore.com"],
"numberOfRuns": 3
},
"assert": {
"preset": "lighthouse:recommended"
}
}
}
Common Pitfalls
Pitfall 1: Secrets in Logs
Never log API keys or tokens. GitHub redacts known secrets, but custom tokens aren't always hidden.
# Bad
- run: echo "Token: ${{ secrets.API_TOKEN }}"
# Good
- run: npm deploy
env:
API_TOKEN: ${{ secrets.API_TOKEN }}
Pitfall 2: Long Workflows That Timeout
Workflows timeout at 6 hours. For long-running jobs, increase parallelization.
# Bad: 6 test suites, running sequentially (2 hours)
- run: npm test
# Good: Test suites run in parallel (30 minutes)
strategy:
matrix:
suite: [unit, integration, e2e]
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: npm test -- --suite=${{ matrix.suite }}
Pitfall 3: Incorrect Branch Protection
Set up branch protection rules to enforce workflow status checks. This prevents merging code that fails tests.
GitHub Settings → Branches → Add rule → Require status checks to pass before merging.
Cost Optimization
For private repos: - 2,000 minutes/month free - Most Shopify workflows: 10–20 minutes per run - If you deploy 10x per day: ~200 minutes/day = 6,000/month
Cost-saving tactics:
1. Run expensive jobs (tests, builds) only on PRs, not every push.
2. Use paths to skip workflows if only docs changed.
3. Cache dependencies with actions/setup-node.
on:
push:
branches: [main]
paths-ignore:
- 'README.md'
- 'docs/**'
Recommended Workflow Sequence
- Day 1: Add template 1 (linting). Takes 1 hour.
- Day 2: Add template 2 (staging deploy). Takes 1 hour.
- Week 1: Add template 4 (automated releases). Takes 30 minutes.
- Week 2: Add template 3 (production approval). Takes 30 minutes.
- Month 1: Add template 6 (Lighthouse audits). Takes 2 hours.
Total setup time: 5 hours. Annual time savings: 50+ hours.
Ready to Automate Your Shopify Development?
GitHub Actions compound your team's efficiency. The first workflow saves an hour per week. The fifth workflow saves 5 hours per week.
Tenten builds custom GitHub Actions workflows for Shopify Plus teams. We design pipelines that match your deployment frequency and team size. Contact us to automate your workflow, or explore Shopify development practices.
Editorial Note
Manual deployments are the biggest time sink in engineering teams. Automate them first, optimize later.
Frequently Asked Questions
What's the difference between GitHub Actions and other CI/CD tools?
GitHub Actions is native to GitHub, free for public repos, and simple to set up. Tools like Jenkins or CircleCI offer more features but require infrastructure.
Can I run private workflows in public repos?
Yes. A public repo can have private GitHub Actions secrets (tokens, keys). The workflow code is public, but the secrets are encrypted.
What happens if a workflow fails?
By default, the push/merge succeeds but the branch is marked as having a failed check. With branch protection rules, failed checks block merges.
How do I debug a workflow that's failing?
GitHub shows logs for each step. Click the workflow run and expand the failed step to see output and error messages.
Can I run workflows on a schedule?
Yes, use schedule with cron. Example: on: schedule: - cron: '0 2 * * *' runs daily at 2am UTC.
How do I cache dependencies to speed up builds?
Use actions/cache@v3 to cache npm modules, Gem bundles, etc. Saves 2–5 minutes per run.
Do I need self-hosted runners for Shopify?
No. GitHub's hosted runners are sufficient for Shopify theme/app deployments. Use self-hosted only for complex builds requiring specific hardware.