Talk Shop
Home
Learn More
About Us
Follow Us
Blog
Tools
Newsletter
Join Discord
Join

Community

  • Developers
  • Growth
  • Entrepreneurs
  • Support
  • Experts
  • Tools

Location

123 Mars, Crater City, Red Planet

(WiFi may be spotty)

Hours

Who has time for breaks? We're here 24/7!

Contact

hello@letstalkshop.com

Talk Shop
Talk Shop

Built for real builders. Not affiliated with Shopify Inc.

Home
Privacy
Terms
  1. Home
  2. >Blog
  3. >Shopify Development
  4. >Shopify Theme Check: Setup, Configuration, and Fixes That Work
Shopify Development14 min read

Shopify Theme Check: Setup, Configuration, and Fixes That Work

Master Shopify Theme Check: correct --path syntax, .theme-check.yml configuration, CI setup, VS Code integration, and fixes for the errors and CLI slowness the official docs gloss over.

Talk Shop

Talk Shop

Jun 11, 2026

Shopify Theme Check: Setup, Configuration, and Fixes That Work

In this article

  • Why the Linter Everyone Ignores Deserves Five Minutes of Setup
  • What Shopify Theme Check Actually Does
  • Installing and Running Your First Check
  • The --path Argument: Syntax That Actually Works
  • Configuring .theme-check.yml the Right Way
  • Inline Disables and Auto-Correct
  • Running Shopify Theme Check in CI
  • VS Code Integration: The Shopify Liquid Extension
  • Common Theme Check Errors and How to Fix Them
  • What You Can and Can't Bypass During shopify theme dev
  • CLI Version Regressions: When Theme Check Feels Broken but Isn't
  • Make the Linter Part of the Team

Why the Linter Everyone Ignores Deserves Five Minutes of Setup

Have you ever pushed a theme update, opened the storefront, and watched a section silently fail to render because of a typo in a Liquid tag? Shopify Theme Check exists to catch exactly that class of mistake before it ships — yet most theme developers either never run it or run it once, get buried under 200 warnings, and never run it again.

That's a configuration problem, not a tool problem. Shopify Theme Check is a static analyzer that reads every Liquid and JSON file in your theme and flags errors, performance issues, and deprecated patterns. Tuned correctly, it becomes a quiet safety net. Left on defaults, it's a noise machine.

This guide covers what the official docs answer badly: the real --path syntax (and why pointing it at a single file doesn't do what you think), .theme-check.yml configuration that actually reduces noise, CI integration, VS Code setup, and the CLI version bugs that make Theme Check feel broken when your code is fine. If you're newer to theme work, skim our Shopify theme development guide for beginners first — this article assumes you have a theme repo and the CLI installed.

What Shopify Theme Check Actually Does

Isometric view of data blocks and a scanner icon representing software linting.

Theme Check is a linter, not a compiler. It parses your theme's Liquid and JSON, runs a battery of named checks against the parse tree, and reports offenses — each tied to a file, a line number, and a check name like ParserBlockingJavaScript or UnusedSnippet.

It ships inside the Shopify CLI today. The original standalone tool lived in the Shopify/theme-check repository, but for modern themes you'll run it through shopify theme check — the CLI bundles the current TypeScript implementation that also powers the VS Code language server.

Linting vs. Validation: Two Different Gates

This distinction matters for troubleshooting later, so get it straight now:

  • Theme Check (linting) runs when you invoke it — manually, in CI, or via your editor. It never blocks shopify theme dev or shopify theme push by default.
  • Platform validation runs server-side on every file upload. A Liquid syntax error that breaks rendering gets rejected by Shopify itself, regardless of your linter config.

You can silence the linter. You cannot silence the platform. Most "I disabled the check but it still fails" confusion comes from mixing these up.

The Three Severity Levels

Every check carries a severity, and you can reassign them in config:

SeverityIntegerMeaning
error0Likely broken behavior — fix before shipping
warning1Risky pattern or performance hit
info2Style and best-practice suggestions

By default a run fails (non-zero exit code) when at least one error-severity offense exists. The --fail-level flag changes that threshold, which becomes important in CI.

Installing and Running Your First Check

If you have the Shopify CLI installed, you already have Theme Check. Confirm with:

bashbash
shopify theme check --version

No install? Get the CLI through npm:

bashbash
npm install -g @shopify/cli@latest

Your First Run

From your theme's root directory (the folder containing layout/, sections/, templates/):

bashbash
shopify theme check

You'll get a list of offenses grouped by file, with the check name in brackets. A fresh Dawn fork typically reports a handful; an older agency theme can report hundreds. Don't panic — most of the noise disappears with ten lines of config, covered below.

Useful Flags to Know on Day One

The full flag list lives in Shopify's theme check CLI reference, but these four do most of the work:

bashbash
shopify theme check --list          # list every enabled check
shopify theme check --print         # output the active config to stdout
shopify theme check -o json         # machine-readable output
shopify theme check --fail-level error   # only exit non-zero on errors
  • --list tells you which checks your config actually enables
  • --print shows the merged config Theme Check resolved — invaluable when an ignore pattern "isn't working"
  • -o json feeds scripts and CI annotations
  • -a / --auto-correct fixes auto-correctable offenses in place

The --path Argument: Syntax That Actually Works

Barcode scanner and a glowing notebook on a dark surface.

This is the part of Shopify theme check that trips up the most developers, so let's be precise. Per the CLI reference, --path is "the path where you want to run the command" — it points at your theme root directory, not at an individual file.

Checking a Theme From Another Directory

The supported use case: you're outside the theme folder, or your theme builds into a subdirectory.

bashbash
# Check the theme in the current directory (default behavior)
shopify theme check --path .

# Check a theme that lives somewhere else
shopify theme check --path ./themes/storefront

# Monorepo or build output: check the compiled theme
shopify theme check --path ./dist

You can also set it via environment variable, which is handy in CI scripts:

bashbash
SHOPIFY_FLAG_PATH=./dist shopify theme check

Why --path path/to/file.liquid Doesn't Do What You Expect

Developers constantly reach for this:

bashbash
# This is NOT a supported way to lint one file
shopify theme check --path sections/header.liquid

The current CLI treats --path as the theme directory to analyze. Single-file and glob targeting was requested by the community in the theme-tools repo, but the CLI's model is whole-theme analysis — checks like UnusedSnippet and TranslationKeyExists require seeing every file to work at all, so a single-file run would produce false positives by design.

How to Check Just One File Anyway

Three honest workarounds, in order of practicality:

  1. Filter the JSON output. Run the whole theme, slice out the file you care about:
bashbash
shopify theme check -o json | jq '[.[] | select(.path | endswith("sections/header.liquid"))]'
  1. Use the VS Code extension's single-file mode. Set themeCheck.onlySingleFileChecks to true and the language server lints only open files, skipping whole-theme checks (details in the VS Code section below).
  2. Scope a custom config. Create a second config that ignores everything except the directory you're iterating on, and load it with -C:
bashbash
shopify theme check -C .theme-check-sections.yml

For a tighter feedback loop than any of these, pair the CLI with an AI coding agent — our walkthrough on Claude Code and Shopify CLI integration shows how to have an agent run the check, parse the JSON, and fix offenses file by file.

Configuring .theme-check.yml the Right Way

Visualization of a configuration file on a dark monitor.

The .theme-check.yml file in your theme root is where Theme Check goes from noisy to useful. Generate a starter file with:

bashbash
shopify theme check --init

The full option reference is in Shopify's Theme Check configuration docs, but here's the working knowledge.

Ignore Patterns That Actually Match

The ignore property takes glob patterns relative to the theme root:

yamlyaml
ignore:
  - 'node_modules/**'
  - 'assets/vendor-*.js'
  - 'snippets/icon-*.liquid'
  - 'templates/customers/**'

Two gotchas worth bolding: patterns must quote-match the path from the theme root, and `--print` is your debugger — if an ignore "isn't working," print the merged config and confirm your pattern survived the merge.

Enabling, Disabling, and Re-Severitizing Checks

Each check is a top-level YAML key. You can toggle it, change its severity, ignore it for specific paths, or set check-specific options:

yamlyaml
# Start from Shopify's recommended baseline
extends: theme-check:recommended

# Kill a check entirely
UnusedAssign:
  enabled: false

# Keep a check but demote it from error to warning
TemplateLength:
  severity: warning
  max_length: 600

# Keep a check everywhere except legacy files
ParserBlockingJavaScript:
  ignore:
    - snippets/legacy-tracking.liquid

The extends key accepts theme-check:recommended, theme-check:all, and theme-check:theme-app-extension — when multiple configs are extended, objects deep-merge and the last entry wins.

A Sane Starter Config for an Inherited Theme

Inherited a ten-year-old theme with 400 offenses? Don't disable everything. Ratchet instead:

yamlyaml
extends: theme-check:recommended
ignore:
  - 'assets/vendor/**'
TemplateLength:
  enabled: false
UndefinedObject:
  severity: warning
Do thisNot this
Demote noisy checks to warning, fix errors firstSet enabled: false on everything that fires
Ignore vendor/generated files by globIgnore entire sections/ or snippets/ dirs
Commit .theme-check.yml to the repoKeep personal configs out of version control
Re-enable one check per sprint and fix itDeclare lint bankruptcy forever

Inline Disables and Auto-Correct

Sometimes one line legitimately violates a rule — a parser-blocking script a third-party app demands, a snippet that looks unused but is rendered dynamically. Disable the check at the call site instead of globally:

liquidliquid
{% # theme-check-disable ParserBlockingJavaScript %}
<script src="{{ 'legacy-widget.js' | asset_url }}"></script>
{% # theme-check-enable ParserBlockingJavaScript %}

Scoping the Disable

Three scopes are supported:

  • Specific check, bounded region — the example above; this should be your default
  • Multiple checks — comma-separate them: {% # theme-check-disable UnusedAssign,SpaceInsideBraces %}
  • Whole file — put {% # theme-check-disable %} on the first line of the file

When Inline Disables Are the Wrong Tool

A disable comment is a documented exception. If you're pasting the same disable into fifteen files, that's a config rule, not an exception — move it to .theme-check.yml. And if you're disabling LiquidHTMLSyntaxError or other parse-level checks, stop: you're hiding a real defect that platform validation will reject at upload anyway. Keep a copy of our Shopify Liquid cheat sheet for developers nearby and fix the syntax instead.

Auto-Correct: What It Fixes and What It Won't

Instead of disabling, let Theme Check repair mechanical offenses — missing defer attributes, whitespace inside braces, simple deprecated-filter swaps — with the auto-correct flag. Run it on a clean git working tree so the diff shows exactly what changed:

bashbash
git status            # confirm clean tree first
shopify theme check -a
git diff              # review every correction

It will not restructure logic, split oversized templates, resolve undefined objects, or fix translation keys — anything requiring intent stays on your plate. Treat -a like a code formatter, not a code reviewer, and never run it for the first time five minutes before a deploy.

Running Shopify Theme Check in CI

Miniature server rack with blue glowing LEDs.

A linter that only runs on your machine protects exactly one machine. Putting Shopify theme check in CI makes it a team contract.

GitHub Actions With theme-check-action

Shopify maintains shopify/theme-check-action, which wraps the CLI and annotates pull requests with inline offense comments:

yamlyaml
# .github/workflows/theme-check.yml
name: Theme Check
on: [push]
jobs:
  theme-check:
    name: Theme Check
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Theme Check
        uses: shopify/theme-check-action@v2
        with:
          theme_root: '.'
          token: ${{ github.token }}

The action accepts a flags input for passing CLI flags (its README uses --fail-level as the example) and a version input to pin a specific @shopify/theme release — pinning matters, as the regressions section below explains.

Choosing a Fail Level

--fail-level sets the minimum severity that produces a non-zero exit code. The pragmatic CI strategy:

  1. Start at `--fail-level error` — block merges only on likely-broken code
  2. Burn down warnings over a few sprints using the ratchet config approach
  3. Tighten the level once the baseline is clean

Failing CI on style suggestions from day one guarantees developers will route around the check.

The Last Line of Defense: theme push --strict

Even without CI, you can make deploys self-checking:

bashbash
shopify theme push --strict

The --strict flag requires Theme Check to pass without errors before pushing — warnings are allowed through. Set SHOPIFY_FLAG_STRICT_PUSH=1 in your deploy environment to enforce it without anyone remembering the flag. For more workflow patterns like this, browse our Shopify development articles.

VS Code Integration: The Shopify Liquid Extension

The same engine behind the CLI powers the official Shopify Liquid extension — install it from the VS Code Marketplace. You get syntax highlighting, completions, Liquid Prettier formatting, and live Theme Check diagnostics as squiggles in the editor.

Setup and Requirements

The extension runs the Theme Check language server, so it expects the Shopify CLI on your machine. It reads the same .theme-check.yml from your theme root, which means editor diagnostics, CLI runs, and CI all agree — one config, three surfaces. If your editor shows offenses the CLI doesn't (or vice versa), run shopify theme check --print and confirm which config each is resolving.

Settings Worth Changing

The defaults check aggressively. Tune them in settings.json:

jsonjson
{
  "themeCheck.checkOnOpen": true,
  "themeCheck.checkOnChange": false,
  "themeCheck.checkOnSave": true,
  "themeCheck.onlySingleFileChecks": true
}
  • checkOnChange: false stops the linter re-running on every keystroke in large themes
  • onlySingleFileChecks: true skips whole-theme checks (UnusedSnippet, TranslationKeyExists) while you're iterating on one file — the closest thing to "check a single file" that exists today

When the Extension Goes Quiet

If diagnostics stop appearing: confirm the CLI is on your PATH, check the extension's output channel for language-server crashes, and make sure you opened the theme root as the workspace folder — opening a parent monorepo folder can keep the server from finding the theme.

Common Theme Check Errors and How to Fix Them

Close-up of a monitor showing a code error panel in a dark setting.

These are the offenses that dominate real-world runs, with the fix that clears each one.

Performance Checks

CheckWhat it meansFix
ParserBlockingJavaScript<script> without defer/async blocks renderingAdd defer (or async for independent scripts)
ImgWidthAndHeight<img> missing width/height causes layout shiftAdd explicit width and height attributes
RemoteAssetAsset served from a third-party domainMove the file to assets/ and use asset_url
AssetSizeJavaScriptJS bundle exceeds the size thresholdSplit bundles; lazy-load below-the-fold scripts

Liquid Correctness Checks

`UndefinedObject` fires when you reference a variable that doesn't exist in that template's scope — frequently a snippet expecting a variable the parent forgot to pass. Fix it by passing the variable explicitly via {% render 'snippet', product: product %}.

`UnusedAssign` flags {% assign %} variables never read; delete them. `UnusedSnippet` flags snippets never rendered — but beware dynamic renders with variable names, which the static analyzer can't follow. That's a legitimate inline-disable case.

`LiquidHTMLSyntaxError` means the parser couldn't build a tree at all. Fix these first: every other check in that file is unreliable until the file parses.

Translation and JSON Checks

`TranslationKeyExists` fires when {{ 'products.product.add_to_cart' | t }} references a key missing from locales/en.default.json. Add the key to the default locale. JSON syntax errors in template or config files are flagged too — and these are worth treating as sacred, because malformed JSON templates get rejected server-side no matter what your linter config says. Theme design choices interact with several of these checks; our theme design archive digs into the performance side.

What You Can and Can't Bypass During shopify theme dev

Here's the mental model that saves hours of confused debugging.

What You CAN Bypass

Everything that belongs to the linter:

  • Check offenses — theme dev does not run Theme Check as a gate; errors and warnings in shopify theme check output won't stop your dev server
  • Editor noise — config ignores, severity demotions, and inline disables all silence diagnostics without touching dev or push
  • Push gating — theme push only consults Theme Check when you pass --strict

What You CANNOT Bypass

Two layers sit beneath your config and don't read .theme-check.yml:

  1. Server-side validation. Files with broken Liquid syntax or malformed JSON get rejected at upload. The dev server logs the upload error and your local change simply never reaches the preview. No config silences this — the file must parse.
  2. The CLI's internal file processing. shopify theme dev parses theme files itself to sync them, and that parsing is not governed by your ignore list. This is exactly what bit users in Shopify CLI issue #5918: theme dev hung for minutes logging LiquidHTMLParsingErrors on themes full of generated snippets (Replo chunks, Zipify pages) — even after adding those files to the `.theme-check.yml` ignore list. The same theme pushed fine, because theme push skipped that processing path.

Practical Escape Hatches

When the un-bypassable layer misbehaves on generated or third-party files:

  • Use shopify theme push + a preview theme as a temporary substitute for theme dev
  • Pin the CLI to the last version that behaved (#5918 reproduced on 3.80.7 but not 3.80.0)
  • Quarantine generated files outside the theme root and copy them in at build time

For more debugging patterns like this, our troubleshooting archive is worth a bookmark.

CLI Version Regressions: When Theme Check Feels Broken but Isn't

Theme Check's reputation suffers for sins committed by the CLI around it. Two documented cases prove the pattern.

The theme dev Hang (#5918)

Covered above: a point release (3.80.0 → 3.80.7) introduced file-checking behavior that hung theme dev for 3+ minutes on snippet-heavy themes before erroring out. Nothing in the theme was newly wrong — the CLI changed underneath it.

The Slow Push Era (#4210)

Shopify CLI issue #4210 documents theme push taking 15 seconds to 2 minutes on themes that uploaded in under 5 seconds on CLI 3.47.x — a regression that coincided with the new colorful upload UI and persisted across versions 3.56–3.64. If your "Theme Check workflow" suddenly feels slow, time the push and the check separately before blaming the linter.

The Defensive Posture

  • Pin your CLI version in package.json rather than installing @latest globally, and pin the version input in theme-check-action
  • Upgrade deliberately — bump in a branch, run theme dev and a full check, then roll forward
  • Bisect by version when behavior changes: npm install -g @shopify/cli@3.80.0 style downgrades take one minute and instantly tell you whether the problem is your code or the tool
  • Search the issue tracker first — third-party writeups like Scale Shopify's Theme Check setup guide are useful for setup, but live regressions surface on GitHub days before anywhere else

Make the Linter Part of the Team

Shopify Theme Check pays for its setup cost the first time it catches a missing translation key or a parser-blocking script before a customer does. The playbook from this guide, compressed:

  • Run shopify theme check --init, extend theme-check:recommended, and commit the config
  • Point --path at the theme root — filter JSON output or use the VS Code single-file mode when you need one file
  • Ratchet severity in .theme-check.yml instead of declaring lint bankruptcy
  • Gate merges with theme-check-action at --fail-level error, and deploys with push --strict
  • Remember the two layers you can't bypass: server-side validation and the CLI's own file processing
  • Pin CLI versions and bisect before assuming your theme is at fault

Theme tooling changes fast — version regressions, new checks, and CLI rewrites all land between doc updates. The fastest way to stay current is to ask people who hit the bug yesterday: the Talk Shop Shopify developer community on Discord is full of theme devs comparing configs, CLI versions, and workarounds in real time. Bring your gnarliest .theme-check.yml and join us — what's the one check you've rage-disabled, and was it ever actually wrong?

Shopify DevelopmentTheme Design
Talk Shop

About Talk Shop

The Talk Shop team — insights from our community of Shopify developers, merchants, and experts.

Related Insights

Related

Headless CMS for Ecommerce: Choosing the Right One for Shopify (2026)

Related

Best Shopify Themes: The Master List, Free and Paid (2026)

New

Business Name Generator

Generate unique, brandable business names with AI. Check domain availability instantly.

Generate Names

Talk Shop Daily

Daily ecommerce news, teardowns, and tactics.

No spam. Unsubscribe anytime. · Learn more

Try our Business Name Generator

Join the Best Ecommerce Newsletter
for DTC Brands

12-18 curated ecommerce stories from 100+ sources, delivered every morning in under 5 minutes. Trusted by 10,000+ operators.

No spam. Unsubscribe anytime. · Learn more

Join the Community

300+ Active

Connect with ecommerce founders, share wins, get feedback on your store, and access exclusive discussions.

Join Discord Server