Shopify CLI Cheat Sheet: theme dev, CI Auth, check and console

Half the Shopify CLI questions I get are the same one: why does shopify theme dev keep opening a browser login in a pipeline that has no browser? The answer is a single environment variable, and it is not the one you would guess from the flag name. This is the copy-paste reference I keep open, weighted toward the part every other cheat sheet skips: running the theme commands non-interactively.

TL;DR: A working Shopify CLI reference for theme developers. It leads with the thing zero-click searchers keep hunting for, running theme commands non-interactively in CI with SHOPIFY_CLI_THEME_TOKEN and SHOPIFY_FLAG_STORE, then covers theme dev, check, console, push and the full lifecycle. Every flag here is checked against the current CLI, not a 2023 tutorial.

Shopify CLI reference in a terminal, the theme dev, check and console commands a Shopify developer runs daily

Download the CLI cheat sheet (PDF)

shopify theme dev, and every flag worth knowing

shopify theme dev starts a local preview server with hot reload against a store. On its first run it opens a browser login unless a token is already in the environment (more on that next). The everyday shape:

shopify theme dev --store my-store
shopify theme dev --store my-store --theme 123456789012   # attach to a specific remote theme
shopify theme dev --live-reload hot-reload                 # hot-reload (default) | full-page | off
shopify theme dev --host 0.0.0.0 --port 9293               # rebind for Docker/WSL
shopify theme dev --theme-editor-sync                      # pull admin editor changes back to local

Two things save real pain here. theme dev creates a temporary development theme that does not count against your theme limit, but it is deleted after 7 days of inactivity and immediately when you run shopify auth logout, so never rely on that preview URL surviving a session. And -a/--allow-live exists to run dev against the live theme: it is blocked by default for a reason, and you do not point it at a client’s live store. The full flag set and the rest of the theme dev workflow sit in Shopify’s command reference.

How do you run shopify theme dev non-interactive (headless CI)?

This is the section everything else is downstream of. To skip the browser login, set two environment variables and let the CLI read them:

export SHOPIFY_CLI_THEME_TOKEN=shptka_xxxxxxxx        # env var for --password
export SHOPIFY_FLAG_STORE=my-store.myshopify.com      # env var for --store
shopify theme dev

The trap that eats hours: the env var for --password is literally SHOPIFY_CLI_THEME_TOKEN, not SHOPIFY_FLAG_PASSWORD. Every other flag follows the SHOPIFY_FLAG_* pattern (SHOPIFY_FLAG_STORE, SHOPIFY_FLAG_PATH, SHOPIFY_FLAG_THEME_ID), and --password is the one irregular exception. Get the name wrong and the command silently falls back to an interactive login and hangs your job.

One more rule that bites: precedence is flag beats env var beats shopify.theme.toml. A stray --store on the command line will quietly override your CI env var. If a step still hangs on a confirmation, add SHOPIFY_FLAG_FORCE=1. And note Shopify’s own CI/CD guide authenticates the same way but runs theme check and theme push, not theme dev.

What is SHOPIFY_CLI_THEME_TOKEN, and how do you get a Theme Access token?

The token is a Theme Access password (or an Admin API token). You generate a Theme Access password from the free Theme Access app on the store. The emailed link expires after 7 days or the moment it is viewed once, so paste the password straight into your CI secrets.

shopify theme push --password shptka_xxxxxxxx --store my-store.myshopify.com   # terminal; use the env var in CI

The scope detail decides whether your script works. A Theme Access password is scoped to write_themes only, which is enough for push, pull, dev and console. A script that also touches products, metafields or other Admin resources needs a custom app access token with those specific scopes instead. That custom-app path is also where unauthenticated_read_content comes in: a themes app needs read_themes and write_themes, plus unauthenticated_read_content (Storefront API) to enable hot reloading. There are three auth methods in total: a Shopify account login, a Theme Access password, and a custom app token.

shopify.theme.toml: named environments, and –password vs –store-password

Stop retyping store, theme and password on every command by putting them in shopify.theme.toml:

[environments.staging]
theme = "123456789012"
store = "my-store"
password = "shptka_123456"
shopify theme dev --environment staging   # or: -e staging

[environments.default] applies automatically without the flag; any other named block needs -e. And the two password flags people constantly mix up are genuinely different: --password is the CLI-to-store auth token (Theme Access or Admin API), while --store-password is the storefront password-page password for a locked store. They solve different problems. Environments work across check, dev, console, delete, info, list, publish, pull, push, rename and share, and the full environments reference documents which keys get ignored inside a block.

shopify theme check: –path vs positional arguments, and CI gating

This resolves a query I see constantly. On the current CLI, --path is the only way to scope a run. There are no positional arguments, so shopify theme check ./sections/header.liquid is invalid; you cannot lint a single file.

shopify theme check --path ./my-theme          # scope to a directory (defaults to cwd)
shopify theme check -a                          # auto-correct fixable offenses in place
shopify theme check --fail-level warning        # exit 1 on warnings (default is error only)
shopify theme check -o json > results.json      # machine-readable, flat array per file
shopify theme check --list                       # every active check + severity

Two current gotchas. The default --fail-level is error, so a CI job that only checks the exit code passes while warnings quietly pile up: pass --fail-level warning to block on them. And --category and --exclude-category were removed in Theme Check 2.x (January 2024), so older posts that show them are wrong now; use -C theme-check:all to run everything, per the theme check reference. This is the linter that keeps a Liquid codebase honest before it ships, and it validates the section schema settings too.

shopify theme console: the offline Liquid REPL

Almost no cheat sheet mentions this one. shopify theme console starts a Liquid REPL: an interactive terminal for evaluating Liquid objects, filters and tags against real store data, with no browser and no running dev server.

shopify theme console
shopify theme console --url /products/classic-leather-jacket   # load real page context
shopify theme console -s my-store.myshopify.com

The one thing that trips people up: without --url, context objects like product, collection and cart return nil, because the REPL has no page context by default. Pass a real relative path and they resolve to live data, which makes it perfect for checking a tricky filter chain or loop before you wire it into a custom section. It has eight flags, no --theme and no --port (those belong to theme dev), and its --password env var is the same SHOPIFY_CLI_THEME_TOKEN.

theme push, pull and publish: the deploy lifecycle

The commands that move code, with the guardrails that stop a bad day:

shopify theme push --unpublished --json                        # new unpublished theme, ids/urls as JSON
shopify theme push --theme 123456789012 --strict               # block push unless theme check passes
shopify theme push --theme 123456789012 --only sections/hero.liquid   # push named files only
shopify theme pull --live --nodelete                            # pull live, keep extra local files
shopify theme publish --theme 123456789012 --force             # promote an already-pushed theme to live

Three traps worth internalising. --nodelete means opposite things by direction: on push it protects remote files, on pull it protects local files. theme publish cannot publish local code, it only promotes a theme you already pushed, so the sequence is always push then publish by id. And --strict blocks only on Theme Check errors, so a push can succeed with warnings still open. Worth knowing for 2026: theme init now clones Shopify’s Skeleton theme by default, not Dawn, which matters when you are choosing a base for a new build or a performance rebuild.

Shopify CLI auth and the global env vars

The session and config commands people still get wrong, because the old names were retired:

shopify auth login                     # not "shopify login"
shopify auth logout                    # warning: deletes any active dev theme
shopify organization list              # replaces the old "shopify whoami"
shopify version
SHOPIFY_CLI_NO_ANALYTICS=1 shopify theme dev --store my-store   # opt out of telemetry

There is no bare shopify login, shopify logout or shopify whoami on the current CLI. Since CLI 4.0 (May 2026) the tool self-upgrades through your package manager by default and skips upgrading inside CI, and it now needs Node 22.12+ and Git 2.28+. SHOPIFY_CLI_NO_ANALYTICS=1 only silences telemetry, it does not suppress prompts, which is SHOPIFY_FLAG_FORCE=1’s job. The complete general-commands list has the rest.

Why theme dev is not your CI command

If you take one habit from this page, take this one. theme dev opens a long-running preview server with hot reload; that is a development tool, not a pipeline step, and dropping it into CI is why so many jobs hang. Shopify’s documented pattern is a linter gate plus a push:

shopify theme check --fail-level error                 # gate: fail the build on errors
shopify theme push --json --theme staging --store $SHOPIFY_FLAG_STORE --password $SHOPIFY_CLI_THEME_TOKEN

For preview-per-PR, shopify theme push --development-context "pr-482" ties a development theme to a stable id like a PR number or branch, which is the idiomatic pattern. Only reach for theme dev in a pipeline for a genuine headless visual-regression run that needs a live URL, and even then remember the dev theme evaporates on logout. Keep the copy-paste reference next to your editor with the PDF above, and pair it with the Liquid cheat sheet for the templating side.

The takeaway

  • Set SHOPIFY_CLI_THEME_TOKEN and SHOPIFY_FLAG_STORE to run any theme command non-interactively, and never reach for SHOPIFY_FLAG_PASSWORD, which does not exist.
  • Generate the token from the free Theme Access app (write_themes scope) and save it to CI secrets before the one-time link expires.
  • Scope theme check with --path only, and pass --fail-level warning so CI actually blocks on lint warnings.
  • Use theme console --url /products/<handle> to test Liquid against real data from the terminal, no browser needed.
  • Keep theme dev out of your pipeline: gate with theme check, deploy with theme push, and download the PDF so every flag is one glance away.

Kaspian Fuad is a Shopify developer and CRO consultant who builds and ships themes through CI for DTC and B2B brands. 12 years in ecommerce, 100+ stores, Top Rated Plus on Upwork. Book a free 30-minute call if you want your theme build and deploy pipeline set up so nothing hangs and nothing touches the live theme by accident.

Frequently Asked Questions

How do I run shopify theme dev without logging in?

Set two environment variables before the command: SHOPIFY_CLI_THEME_TOKEN (a Theme Access password or Admin API token, the env-var equivalent of –password) and SHOPIFY_FLAG_STORE (your store domain). With both set, the CLI skips the interactive browser login. The one-liner is: SHOPIFY_CLI_THEME_TOKEN=shptka_xxx SHOPIFY_FLAG_STORE=my-store.myshopify.com shopify theme dev.

What is SHOPIFY_CLI_THEME_TOKEN?

It is the environment variable that holds your theme auth token, and it is the env-var equivalent of the –password flag. It is the one irregular exception to Shopify’s SHOPIFY_FLAG_* naming pattern, so do not use SHOPIFY_FLAG_PASSWORD. Setting the wrong name is the top reason CI theme commands silently fall back to an interactive login and hang.

How do I get a Shopify Theme Access token for CI?

Install the free Theme Access app on the store and generate a password. It is scoped to write_themes only, which covers push, pull, dev and console. The emailed link expires after 7 days or once viewed, so save the password immediately into your CI secrets as SHOPIFY_CLI_THEME_TOKEN. For work that also touches products or metafields, use a custom app access token instead.

Does the Shopify CLI need unauthenticated_read_content?

Only on the custom app access token path. A custom app used for themes needs read_themes and write_themes, plus unauthenticated_read_content (Storefront API) to enable hot reloading, and those tokens must be passed as environment variables. A Theme Access app password is documented as write_themes only, so verify hot reload with a live smoke test before assuming it needs the Storefront scope.

What is the difference between shopify theme check --path and a positional argument?

–path is the only way to scope a run. The current CLI takes no positional file or directory arguments, so shopify theme check ./sections/header.liquid is invalid. Use shopify theme check –path ./my-theme on a directory (it defaults to the current working directory). You cannot lint a single file.

How do I make Shopify theme check fail CI on warnings?

Pass –fail-level warning. The default fail-level is error, so a run with only warnings exits 0 and a CI job checking the exit code passes. shopify theme check –fail-level warning makes any warning-or-worse offense exit 1. Accepted levels include crash, error, suggestion, style, warning and info.

What does shopify theme console do?

It starts the Shopify Liquid REPL, an interactive terminal for evaluating Liquid objects, filters and tags against real store data, with no browser or running dev server needed. Pass –url /products/ to load page context so context-dependent objects resolve instead of returning nil. It has no –theme or –port flag; those belong to theme dev.

Should I use theme dev in a CI/CD pipeline?

No. theme dev opens a long-running local preview server with hot reload, which is not a pipeline step. Shopify’s own CI/CD pattern uses shopify theme check to gate and shopify theme push to deploy, authenticated with SHOPIFY_CLI_THEME_TOKEN and SHOPIFY_FLAG_STORE. Only use theme dev in CI for a headless visual-regression run that needs a live preview URL.
Book Strategy Call