ezomfy
All posts
June 26, 20268 min read

Why Your Shopify Theme Needs Theme Check in CI

Shopify Theme Check prevents Liquid errors before they hit production, yet most agencies skip it in CI. I'll show how to integrate it into GitHub Actions to block faulty PRs, saving countless emergencies.

A

Ashraful

Shopify Select Partner

Close-up of hands on a laptop browsing an e-commerce site in a modern office. — Photo by Shoper .pl on Pexels

I've shipped over 700 Shopify projects, and I've seen the same pattern repeat dozens of times: a seemingly minor Liquid change goes live, breaks a critical store function, and then it's a scramble to fix. This isn't just about bad code; it's about a lack of process. Specifically, it's about ignoring a foundational tool that Shopify themselves provides: Theme Check.

Most development agencies, even the "good" ones, don't run Shopify Theme Check in their Continuous Integration (CI) pipelines. This is a massive oversight. Theme Check catches Liquid, JSON, and CSS/JS syntax errors, performance anti-patterns, and even security vulnerabilities before your code ever reaches production. My argument is simple: if you're building Shopify themes, Theme Check needs to be a mandatory gate in your CI. It takes 10 minutes to set up and can save you from 10 client emergencies.

Why Shopify Theme Check in CI is Non-Negotiable

Theme Check is Shopify's official linter for Liquid, JSON, and other theme files. It's designed to catch common errors, enforce best practices, and identify potential performance bottlenecks. Think of it as ESLint or Prettier, but for your Shopify theme code.

I've been a Shopify Select Partner since 2021, and I've audited countless theme codebases. What I consistently find is that while developers might know about Theme Check, almost no one integrates it into their automated workflows. They might run it manually occasionally, or worse, not at all. This leaves a gaping hole in their quality assurance process.

Here's why relying on manual checks is a terrible idea:

  • Human Error: Developers forget. They're busy. They're under pressure. Manual steps are skipped, leading to inconsistencies and missed issues.
  • Inconsistency: What one developer checks, another might not. Coding standards erode over time without automated enforcement.
  • Late Detection: Errors are found during manual QA, or worse, by the client or their customers in a live environment. This is expensive to fix, damages trust, and can lead to lost sales.

By embedding Shopify Theme Check directly into your CI pipeline, you automate this crucial step. Every Pull Request (PR) is automatically scanned, and if it fails the checks, it simply cannot merge. This isn't about being draconian; it's about building robust, reliable stores from the ground up. It ensures a baseline level of quality and consistency across your entire team's contributions, making code reviews faster and more focused on logic rather than syntax.

The Mistake Most Agencies Make: Trusting "Good Enough"

The mistake I see most often is agencies relying on visual QA alone, or basic syntax highlighting in their IDE. They push code, someone looks at it on a staging environment, and if it "looks fine," it goes to production. This approach is fundamentally flawed for Shopify theme development.

Liquid isn't like React or Vue where a compiler will throw a fit if you misspell a component or forget a closing tag. Liquid is interpreted at runtime. A simple typo like assign product = prooducts.first instead of products might not crash the page, but it will silently fail to assign the product, leading to incorrect data display, broken buy buttons, or missing content. These are the kinds of subtle, hard-to-debug issues that Theme Check excels at finding. It can pinpoint performance issues like excessive database queries or asset sizes, and even security risks such as unescaped output.

A Client War Story: The Missing Product Loop

I once took over a project for a client, a high-growth fashion brand, whose previous agency had delivered a custom theme. They were complaining about inconsistent product displays on collection pages. Sometimes, product images wouldn't load, or the "add to cart" button would be missing. It was intermittent and maddening for them.

When I pulled down the theme and ran Theme Check, it immediately flagged a dozen warnings and errors. One critical error was a Liquid loop structured incorrectly, causing it to sometimes iterate over an empty array if a specific product tag wasn't present, even though the intent was to show all products. The previous agency's manual QA had missed this because it only manifested under specific data conditions not always present in their staging environment. Setting up Theme Check in CI for them would have caught this in minutes, not months after launch. This experience solidified my belief that automated checks are paramount for reliable theme development, like the specialized theme development services I offer at ezomfy.com/services/theme-dev.

Setting Up Shopify Theme Check in GitHub Actions

Okay, enough theory. Let's get practical. I'll show you how to set up Theme Check as a GitHub Action. This will run every time you push code to a PR, and it will fail the PR if any critical Theme Check errors are found.

First, you need to have Theme Check installed. It's a Ruby gem, but the easiest way to use it in a CI context is often via npx if you have Node.js installed, as many front-end projects do. Shopify provides a CLI tool that wraps Theme Check, making it simple to integrate into an existing npm or yarn workflow.

Step 1: Install Shopify CLI (if not already present)

While you can install the Theme Check gem directly, using the Shopify CLI is generally more robust for CI environments as it handles dependencies and keeps everything updated. If you don't already have @shopify/cli installed as a dev dependency, add it to your package.json.

Your package.json might look something like this, with a script for Theme Check:

{
  "name": "my-shopify-theme",
  "version": "1.0.0",
  "scripts": {
    "theme:check": "shopify theme check",
    "theme:dev": "shopify theme dev",
    "theme:push": "shopify theme push"
  },
  "devDependencies": {
    "@shopify/cli": "^3.0.0"
  }
}

After adding the dev dependency, run npm install. Then, you can run npm run theme:check locally to test it out.

Step 2: Configure Theme Check Rules (Optional but Recommended)

By default, Theme Check uses a sensible set of rules. However, you might want to customize them. You can create a .theme-check.yml file in the root of your theme directory. This allows you to disable certain checks that might not apply to your workflow, or elevate the severity of others.

Here’s an example .theme-check.yml that disables a few checks I often find too strict for client projects and makes a critical HTML parsing error fail a build:

# .theme-check.yml
# See https://shopify.dev/docs/themes/tools/theme-check/configuration
root: "./"
ignore:
  - "node_modules/**"
  - "assets/*.js"
  - "assets/*.css"
  - "sections/*.liquid" # Example: ignore a specific file if needed

# Adjust check severities or disable them
check_configs:
  HtmlParsingError:
    severity: error # Make sure HTML parsing errors are always errors
  MissingTemplate:
    severity: error
  DeprecatedFilter:
    severity: warning # Log deprecated filters as warnings, not errors
  MatchingTranslations:
    enabled: false # Disable this check if you're not using translation keys consistently
  RequiredLayoutThemeFile:
    enabled: false # If you have a custom layout strategy that doesn't use theme.liquid
  TranslationKeyExists:
    severity: warning # We want to know, but not fail PRs immediately

This file gives you fine-grained control. I prefer to make HtmlParsingError an error because broken HTML is almost always a bug. I might set MatchingTranslations to false on some projects where translation consistency isn't the highest priority during initial development. Tailor this to your project's needs and your team's coding standards.

Step 3: Create the GitHub Actions Workflow

Now, let's create the actual CI workflow. In your theme repository, create a file at .github/workflows/theme-check.yml. This file defines the steps GitHub Actions will take to run Theme Check.

name: Shopify Theme Check

on:
  pull_request:
    branches:
      - main
      - master
  push:
    branches:
      - main
      - master

jobs:
  theme_check:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18' # Or your preferred Node.js version

      - name: Install dependencies
        run: npm install

      - name: Run Shopify Theme Check
        run: npm run theme:check -- --fail-on=error # Fails the action if any errors are found

Let's break down this GitHub Actions file:

  • name: Shopify Theme Check: A human-readable name for your workflow, which will appear in GitHub's checks UI.
  • on: pull_request and on: push: This workflow will trigger on every pull_request against main or master branches, and also on push to those branches. I recommend pull_request as the primary trigger so errors are caught before merging.
  • jobs: theme_check: Defines a single job within the workflow. You could have multiple jobs if you had other CI steps.
  • runs-on: ubuntu-latest: The job will run on a fresh Ubuntu virtual machine provided by GitHub Actions.
  • steps:
    • actions/checkout@v4: This action checks out your repository code into the runner's environment.
    • actions/setup-node@v4: This sets up Node.js, which is needed for npm install and the Shopify CLI. Choose a Node.js version compatible with your project.
    • npm install: Installs your devDependencies, including @shopify/cli, from your package.json.
    • npm run theme:check -- --fail-on=error: This is the crucial step. It executes the theme:check script we defined in package.json. The -- --fail-on=error argument tells Theme Check to exit with a non-zero status code (which fails the GitHub Action) if any errors are detected. You could change this to --fail-on=warning if you want to be even stricter, but I typically start with error to block critical issues without being overly prescriptive on minor warnings.

Making Theme Check a PR Blocker

Running the workflow is one thing; making it a required check is another. This is where you actually block merges, ensuring no code with detected errors makes it into your main branch.

In your GitHub repository settings:

  1. Go to Settings -> Branches.
  2. Select the branch you want to protect (e.g., main or master).
  3. Click Add rule.
  4. Under Require status checks to pass before merging, search for "Shopify Theme Check" (or whatever you named your workflow).
  5. Check the box next to it. This links your workflow's success to the PR's mergeability.
  6. Ensure Require branches to be up to date before merging is also checked (good practice for avoiding merge conflicts).
  7. Save changes.

Now, any Pull Request targeting your protected branch will require the "Shopify Theme Check" workflow to pass before it can be merged. If Theme Check finds an error, the PR will show a red X, and the merge button will be disabled. Your developers will be forced to fix the Liquid before shipping it. This automated gate ensures that a baseline quality is met with every single code change.

This process takes maybe 10 minutes to set up, and it immediately elevates your team's code quality and reduces the risk of production outages due to theme errors. It's a small investment for a massive payoff in stability, developer sanity, and ultimately, client satisfaction.

Beyond Basic Checks: Custom Rules and Best Practices

While Theme Check's built-in rules are excellent, for larger agencies or very specific project requirements, you might want to extend its capabilities with custom checks. This is where you can define rules specific to your internal coding standards or unique Liquid patterns that are critical for your projects.

For instance, if your agency always uses a specific naming convention for sections or snippets, you can create a custom check to enforce it. Or, if you have a strict policy against using certain global objects directly in Liquid to maintain performance or prevent data exposure, you can write a check for that. This level of customization ensures that your themes not only meet Shopify's general standards but also your own bespoke requirements, making your codebase uniquely robust.

I've worked with numerous clients to develop custom Theme Check configurations that align with their long-term maintenance goals and internal development guidelines. It's a key part of building sustainable and high-performing Shopify stores, and something I often help clients with through my Shopify theme development services.

How Custom Checks Work

Custom checks are typically written in Ruby and live within your theme's directory, often in a lib/theme_check folder. You then reference them in your .theme-check.yml to ensure they are run alongside Shopify's default checks.

For example, a simple custom check might look for specific comments (e.g., a required copyright header) or ensure all {% schema %} tags have a name property, which is crucial for theme editor usability.

# lib/theme_check/checks/my_custom_check.rb
module ThemeCheck
  class MyCustomCheck < Check
    def initialize(config)
      super
      @offenses = []
    end

    def on_schema(node)
      # Ensure all schema tags have a 'name' property
      if node.schema["name"].nil? || node.schema["name"].empty?
        add_offense("All schema tags must have a 'name' property for editor visibility.", node)
      end
    end

    def offenses
      @offenses
    end

    private

    def add_offense(message, node)
      @offenses << Offense.new(
        check: self,
        message: message,
        template: node.template,
        line_number: node.start_line_number,
        markup: node.markup,
        severity: :error
      )
    end
  end
end

Then, in your .theme-check.yml, you'd include your custom check:

# .theme-check.yml
root: "./"
require:
  - "./lib/theme_check" # Path to your custom checks folder

check_configs:
  MyCustomCheck:
    enabled: true
    severity: error

This ensures that your team adheres to specialized requirements, making your codebase more consistent and easier to maintain in the long run. It's a powerful way to codify your team's institutional knowledge and prevent common project-specific errors.

This isn't about adding unnecessary overhead. It's about building a robust development process that catches problems early, saves time, and prevents client headaches. If you're serious about delivering high-quality Shopify themes, Theme Check in CI isn't optional; it's fundamental.

If you're struggling with consistent theme quality, or if you're an agency looking to implement more robust CI/CD practices for your Shopify projects, I offer free 30-minute consultation calls. We can discuss your specific challenges and explore how you can streamline your development workflow to avoid preventable errors. Book a call at ezomfy.com/consultation.

A

About the author

Ashraful

Shopify Select Partner, Top Rated Plus on Upwork. 700+ Shopify projects shipped over 7+ years — themes, apps, migrations, speed, Hydrogen. Solo shop, no agency middlemen.

Read the full story

Working on a Shopify project?

That's what I do every day. Pick whichever feels lower-friction.