Shopify Theme Check: Why a Single File Path Argument Does Not Work (and What to Do Instead)
Passing a single file path to shopify theme check fails silently or errors out.
Running shopify theme check ./sections/header.liquid does nothing useful. The command is syntactically invalid on the current CLI: Theme Check does not accept a positional file path argument. The correct scope flag is --path, and it only accepts a directory, not a single file. Here is exactly what works, why single-file linting works differently than you expect, and how to wire it into CI properly.
Key takeaways
shopify theme check ./sections/header.liquidis invalid on the current Shopify CLI. There are no positional file arguments.- Use
--pathto point at a directory (defaults to the current working directory if omitted). - True single-file feedback comes from the VS Code Language Server (
themeCheck.onlySingleFileChecks), not the CLI. - The default
--fail-leveliserror, so CI passes silently while warnings pile up. Always pass--fail-level warning. - As of Shopify CLI 4.0 (May 2026), the tool needs Node 22.12+ and auto-upgrades through your package manager outside of CI.
The exact mistake most developers make
You are editing sections/hero.liquid, you spot a potential lint issue, and you type:
shopify theme check ./sections/hero.liquid
Nothing useful happens. On the current CLI, that positional argument is simply ignored or produces an error about a missing theme directory.
This confusion has a specific cause: Theme Check 2.x (the Node-based version shipped inside Shopify CLI) replaced the older Ruby gem, and the Ruby gem did accept a path positional argument. Older tutorials, StackOverflow answers, and blog posts written before the Theme Check 2.x migration (finalised in early 2024, with --category and --exclude-category removed at the same time) still show the old syntax. Those posts are wrong now.
As confirmed by Shopify's own CLI reference, --path is the only way to scope a run, and it scopes to a directory, not a file.
What the flag actually does
# Scope to a specific theme directory
shopify theme check --path ./my-theme
# Defaults to the current working directory
shopify theme check
# Auto-correct fixable offenses in place
shopify theme check -a
# Change what severity level causes a non-zero exit
shopify theme check --fail-level warning
# Machine-readable output (flat array per file)
shopify theme check -o json > results.json
# List every active check and its severity
shopify theme check --list
--path tells Theme Check which directory to treat as the theme root. Every file inside that directory (templates, sections, snippets, layout, assets) gets checked in one pass. You cannot narrow it to a single file at the CLI level.
How to actually lint a single file: the Language Server approach
The CLI is a whole-theme tool. Single-file feedback is the job of the Shopify Liquid Language Server, which powers the Shopify Liquid VS Code extension.
The extension exposes a setting called themeCheck.onlySingleFileChecks. When set to true, it disables whole-theme checks (such as UnusedSnippet and TranslationKeyExists) and only checks whichever files are currently open in the editor. This makes textDocument/didChange checks run roughly 125x faster compared to full-theme re-checks on every keystroke.
Add this to your VS Code workspace settings:
{
"themeCheck.checkOnOpen": true,
"themeCheck.checkOnChange": true,
"themeCheck.checkOnSave": true,
"themeCheck.onlySingleFileChecks": true
}
The trade-off: you will miss cross-file checks while coding. The recommended pattern is to run onlySingleFileChecks: true locally for speed, then run the full shopify theme check on the whole theme in CI before any push.
Comparison: CLI vs Language Server for single-file feedback
| Approach | Scope | Speed | Cross-file checks | When to use |
|---|---|---|---|---|
shopify theme check (no flags) | Whole theme (cwd) | Seconds to minutes | Yes | Pre-push gate, CI |
shopify theme check --path ./dir | Named directory | Same as above | Yes | Monorepo sub-themes |
VS Code + onlySingleFileChecks: true | Open files only | ~10ms per change | No | Active development |
VS Code + onlySingleFileChecks: false (default) | Whole theme via LSP | ~1250ms per change | Yes | Pre-commit local review |
The --fail-level gotcha that silently breaks CI
This trips up almost every team that sets up a lint gate for the first time.
By default, --fail-level is set to error. That means a run that finds only warnings exits with code 0. Your CI job checks the exit code, sees 0, marks the step green, and those warnings quietly accumulate across dozens of PRs until someone finally notices a deprecated filter or a performance smell that has been sitting in production for months.
Fix it in one line:
shopify theme check --fail-level warning
Accepted levels, from most to least strict:
infosuggestionstylewarningerror(default)crash
For most stores, warning is the right threshold. It catches real problems without blocking on purely stylistic suggestions.
A production-grade CI pattern (GitHub Actions)
Below is the minimal, current pattern. It uses SHOPIFY_CLI_THEME_TOKEN for non-interactive auth and gates the build on Theme Check before any push.
name: Theme Lint and Deploy
on:
push:
branches: [main]
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install Shopify CLI
run: npm install -g @shopify/cli @shopify/theme
- name: Run Theme Check
run: shopify theme check --path . --fail-level warning -o json > tc-results.json
env:
SHOPIFY_FLAG_STORE: ${{ secrets.SHOPIFY_STORE }}
- name: Upload results
if: always()
uses: actions/upload-artifact@v4
with:
name: theme-check-results
path: tc-results.json
deploy:
needs: lint
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install Shopify CLI
run: npm install -g @shopify/cli @shopify/theme
- name: Push theme
run: shopify theme push --json --theme ${{ secrets.SHOPIFY_THEME_ID }}
env:
SHOPIFY_CLI_THEME_TOKEN: ${{ secrets.SHOPIFY_CLI_THEME_TOKEN }}
SHOPIFY_FLAG_STORE: ${{ secrets.SHOPIFY_STORE }}
Note that --strict on theme push blocks only on Theme Check errors, so passing --fail-level warning in the dedicated check step is the correct gate, not relying on --strict alone.
Three more flags worth knowing
-a/--auto-correct: fixes offenses that Theme Check can resolve without human judgment (spacing inside{% %}, unused assigns). Run this locally, never blindly in CI.--list: prints every enabled check and its severity. Useful when a team member adds a.theme-check.ymland you want to verify the active rule set before a release.-C theme-check:all: enables every available check, including ones disabled intheme-check:recommended. Use this for a periodic deep audit, not as a daily gate.
What changed in CLI 4.0 (May 2026) that affects your setup
If your pipeline started behaving oddly after May 2026, the cause is likely Shopify CLI 4.0. Two things changed that affect theme check runs:
- Node 22.12+ is now required. Pipelines pinned to Node 18 or 20 will fail at the install step.
- Auto-upgrade is skipped in CI. The CLI detects CI environments and does not self-update, which is the correct behaviour. But project-local installs also skip auto-upgrade, so make sure your pipeline explicitly installs the version you want.
As a bonus, theme init now clones Shopify's Skeleton theme by default instead of Dawn. That does not affect Theme Check behaviour, but it matters if you are scaffolding a new project in the same pipeline.
Common .theme-check.yml mistakes
Your .theme-check.yml file sits at the theme root and controls which checks run and at what severity. A few patterns that cause confusion:
# Correct: extend from recommended, then override
extend: theme-check:recommended
TemplateLength:
enabled: false
UnusedAssign:
severity: suggestion # downgrade from warning
ParserBlockingJavaScript:
enabled: true
severity: error
- Do not use
--categoryor--exclude-category. These flags were removed in Theme Check 2.x. Use the YAML file instead. - The
rootkey is only needed when your theme files live in a subdirectory (e.g. a build output folder likedist/). You do not need it for a standard Dawn or Horizon structure.
For a broader look at how Theme Check fits into a full Shopify theme workflow, see my guide to Shopify theme development and Liquid best practices.
If you are wiring this into a CI/CD pipeline as part of a larger migration or build system, the Shopify theme developer service page covers how we approach automated quality gates on client projects.
Frequently asked questions
Can I pass a single file path to shopify theme check on the command line?
No. The current Shopify CLI (Theme Check 2.x) does not accept positional file path arguments. Passing a file path like ./sections/header.liquid is invalid. Use --path to point at a directory, or use the VS Code Language Server with onlySingleFileChecks enabled for per-file feedback during development.
What does the --path flag do in shopify theme check?
The --path flag tells Theme Check which directory to treat as the theme root. It defaults to the current working directory if omitted. You cannot use it to target a single file; it must be a directory containing your theme folders (templates, sections, snippets, etc.).
Why does my CI pipeline pass even though shopify theme check found warnings?
The default --fail-level is error, which means runs that only produce warnings exit with code 0 and your CI step shows green. Pass --fail-level warning to make the job exit with a non-zero code whenever any warning-or-worse offense is detected.