Skip to main content

Migrate to Shopify CLI 5.0

Shopify CLI 5.0 changes JSON output contracts for theme commands, Shopify Functions, app configuration validation, channel configuration imports, store GraphQL execution, and subscription migrations. Update scripts, CI workflows, and integrations that consume these outputs. Function run and finite replay commands also buffer text output until execution completes.

Shopify CLI 5.0 also removes the app logs and app logs sources commands. To see Function logs from your dev preview, use app dev.

JSON contracts follow the CLI version. A breaking result change requires a major CLI version. Native content, such as GraphQL query data, Function runner output, TOML, and Speedscope profiles, retains its own field names and format.


  • Check the Shopify CLI requirements.
  • If you're upgrading from Shopify CLI 3.x, then complete the 4.0 migration first.
  • Identify scripts that parse output from the affected commands.
  • Save representative output from your current version, including empty results and failures, so you can compare your script's behavior after migration.

Anchor to Step 1: Install Shopify CLI 5.0 in a test environmentStep 1: Install Shopify CLI 5.0 in a test environment

Install Shopify CLI 5.0 in a test environment before updating your scripts or production automation. Shopify CLI doesn't upgrade automatically across major versions, so install 5.0 manually. For a global npm installation, use:

terminal

npm install -g @shopify/cli@5
shopify version

For a project-local installation, update its @shopify/cli dependency and commit the lockfile.

Shopify CLI 4.x output doesn't match the 5.0 contracts. Update your scripts against the test installation, and release your script changes together with the CLI version change after verification.


Anchor to Step 2: Update JSON consumersStep 2: Update JSON consumers

Pass --json explicitly when you need machine-readable output. Use --no-input separately when a command must run without prompting, and supply its required input flags.

Finite commands, which exit after they produce a result, write that result to stdout. Parse stdout as one JSON document. Progress and diagnostics use JSON events on stderr. Keep the streams separate instead of parsing combined stdout and stderr as a result. app dev --json streams JSON Lines (JSONL) instead, as described in Step 3.

Anchor to Collections and resource objectsCollections and resource objects

Update array iteration and property lookups for named collections and resources:

CommandEarlier output5.0 migration
theme listRoot array of themesRead themes. Theme IDs are strings.
app function infoFunction properties at the rootRead the function object and its targets array.

An empty collection remains an array inside its object. For example, an empty theme library returns {"themes": []}.

The following examples show the theme list migration:

[
{
"id": 123,
"name": "Example theme",
"role": "unpublished",
"processing": false,
"createdAtRuntime": false
}
]
{
"themes": [
{
"id": "123",
"name": "Example theme",
"role": "unpublished",
"processing": false
}
]
}

Anchor to IDs, timestamps, and missing valuesIDs, timestamps, and missing values

Update parsers and comparisons for the conventions used by the affected commands:

Value5.0 contractRequired update
Theme IDsDecimal strings in id and developmentThemeId.Compare theme IDs as strings.
Subscription migration GIDsgid, shopGid, operationGid, or operationGids, depending on the result.Replace the earlier ID field names with the mappings in Step 3.
Subscription notification instantsWhole-second UTC timestamps, such as 2026-09-30T10:20:30Z.Remove dependencies on display dates, fractional seconds, or timezone offsets.
Subscription calendar datesYYYY-MM-DD.Parse these fields as calendar dates. Don't assume every date field includes a time.
Unavailable resource valuesnull where the command's schema specifies an unavailable value.Handle null instead of treating an empty string as an unknown value.
Empty collections[] under the named collection.Handle an empty array without treating it as an error or missing result.
Filesystem pathsAbsolute paths in the operating system's native format.Use path utilities that support the platform where the command runs.

CLI-owned field names use camelCase. Native content, such as GraphQL query aliases and Function runner memory_usage, keeps its original spelling.


Anchor to Step 3: Update affected commandsStep 3: Update affected commands

Each of the following sections covers one command group. Update the scripts that use those commands, and skip the sections for commands you don't use.

Use string-valued IDs and the following field mappings:

CommandRequired update
theme infoUse storeDomain, developmentThemeId, cliVersion, and nodeVersion. When a theme is selected, read its storeDomain, previewUrl, and editorUrl inside theme. Handle unavailable values as null.
theme listIterate over themes. Stop reading the internal createdAtRuntime field.
theme openRead URLs inside theme.previewUrl and theme.editorUrl, and use theme.storeDomain. theme.src becomes theme.sourceUrl, with null when unavailable.
theme duplicateRead status, changed, originalTheme, and theme. Use theme.storeDomain and theme.previewUrl. Cancellation returns status: "cancelled", and failure uses the fatal error document.
theme pushRead status, changed, theme, and issues. Replace the nested error map with issues[].filePath and issues[].message. Partial uploads return status: "partial" and exit nonzero while retaining completed work.
theme previewCheck status: "success". Read the URL from preview.url and the opaque string identifier from preview.id, replacing the root url and preview_identifier fields.
theme checkRead valid, flat issues, errorCount, warningCount, and infoCount. Replace file-grouped offenses with issues[].filePath. Position fields use startRow, startColumn, endRow, and endColumn, with one-based lines and columns: the first line and column are 1. Remove any +1 conversion used to display these positions. The new report also applies to --output json.
theme profilePreserve the native Speedscope profile. When --environment is explicit, read it from that environment's result in the batch object.

Use the environment batch format in Step 4 whenever you explicitly pass --environment to these theme commands, including for one environment.

Remove --poll from theme dev invocations in your scripts. Shopify CLI 5.0 removes the flag. It has been deprecated since 3.61.0 and has had no effect since 3.70.0, so you don't need a replacement.

Anchor to Shopify Functions commandsShopify Functions commands

For app function info, read function.targets as an array of records with target, inputQueryPath, and export. Replace lookups by target name in the former targeting object with a search by target. Use function.apiVersion and function.schemaPath, and handle unavailable values as null.

app function run preserves the native Function runner JSON fields, including memory_usage. A completed execution with success: false retains its result and exits nonzero. Setup failures, invalid runner output, and process failures use the fatal error document. Read diagnostics from stderr. Finite text output is buffered until execution completes.

Finite app function replay --no-watch text output also waits until replay completes. For finite JSON replay, pass --no-watch:

terminal

shopify app function replay --no-watch --json

Don't combine the finite JSON result with replay's watch mode.

Anchor to App development sessions and JSON streamingApp development sessions and JSON streaming

Use app dev --json to consume development output without parsing terminal text. For unattended runs, also pass --no-input and provide the configuration and store required for your session:

terminal

shopify app dev --json --no-input

Parse stdout one line at a time. Each dev stream record has timestamp, source, and message, with level when available. Records include process output, preview URLs, and preview status messages. There isn't a final success result. Setup messages and diagnostics use stderr, and setup prompts still require input unless you pass --no-input.

Preview errors appear as log records while the session keeps running so you can fix your app. Fatal CLI failures write an error object to stdout and exit nonzero. Handle both log records and fatal errors when reading the stream.

Shopify CLI records each session's metadata and JSONL log under .shopify/dev/, including when you run without --json. In JSON mode, stdout contains the same dev stream records as the session log. These records contain text messages. They don't replace the structured Function log files in .shopify/logs.

Before starting another session for the same project and app configuration, reuse the running session or stop it. A second invocation exits with error.code: "dev_instance_already_running". Read the existing session's metadata for its PID, URLs, logFile, and details.preview status. The preview status describes the CLI's state. It isn't an application health check.

Inspect the stream, fatal error, and session-file schemas with:

terminal

shopify app dev --json-schema

Anchor to App configuration validation and channel importsApp configuration validation and channel imports

For app config validate, read diagnostic paths from issues[].filePath and issues[].fieldPath instead of file and path. fieldPath is an array of configuration keys and indexes, or null. code is null when unavailable. A completed validation returns its valid result even when validation fails. Setup failures return a fatal error document.

For app import channel-config, check status: "success" and use the absolute path of the written file. The native TOML stays in toml.

Anchor to Store GraphQL executionStore GraphQL execution

For store execute --json, read your query's result under data. Optional response metadata appears under extensions. Query field names and aliases inside data don't change.

For example, change a lookup of products.nodes to data.products.nodes:

{"products": {"nodes": []}}
{"data": {"products": {"nodes": []}}}

GraphQL failures use the fatal error document. Read upstream errors from error.details.errors, response metadata from error.details.extensions, and partial query data from error.details.data when available.

With store execute --json --output-file, the file contains the same data and optional extensions wrapper. Read the result from that file. Successful file output doesn't write a result or receipt to stdout.

Anchor to Subscription migrationsSubscription migrations

Update consumers of app subscription-migrations list, status, schedule, unschedule, and cancel:

Earlier field or behavior5.0 migration
Operation idRead gid.
References named operationId or operationIdsRead operationGid or operationGids in the corresponding result.
Subscription or result shopIdRead shopGid.
results.edges[].nodeIterate directly over results.
User error fieldRead the array-valued fieldPath.
Schedule or unschedule fields under submissionRead clientId, action, inputDigest, total, and operations at the root, alongside status and changed.
Submission failure with completed batchesHandle status: "partial", preserve operations, and inspect failure.
Declined schedule or unschedule confirmationHandle status: "cancelled", changed: false, and the cancellation reason, with exit code zero.

Cancellation returns an overall success or partial status and an operations array. Each item has its own status and operation GID. Failed items retain their structured error details. Don't discard successful items when another cancellation fails.

For subscription dates, notification instants use whole-second UTC timestamps. effectiveDate retains a YYYY-MM-DD calendar date when that's what the source supplies. Upstream status and reason strings can gain new values, so handle values your integration doesn't recognize.

Shopify CLI 5.0 removes app logs and app logs sources. Running either command returns an error and exits nonzero. To see Function logs, run shopify app dev.

app dev only shows logs from your developer preview. It can't watch the released app version. To inspect Function runs from the released version, use Function run logs in the Dev Dashboard.

While app dev runs and your app has at least one Function extension, it streams Function run and network access logs from the dev store to your terminal. It also writes each log to a separate JSON file in your app's .shopify/logs directory, named <timestamp>_<namespace>_<handle>_<id>.json. Timestamps are in UTC, so sorting the filenames sorts the logs by time. app function replay reads the same files.

The following ls and jq examples read the log files that exist when you run them. They don't stream new logs. Run them again to include files written later.

Earlier usage5.0 migration
app logsRun app dev. Each log appears in the terminal with a link to its file.
app logs sourcesUse the handle from each Function extension's shopify.extension.toml. Each source is named extensions.<handle>.
--source extensions.<handle>List the matching files with ls .shopify/logs/*_extensions_<handle>_*.json, or filter with jq -c 'select(.source == "<handle>")' .shopify/logs/*.json.
--status success or --status failureFilter on the top-level status, for example jq -c 'select(.status == "failure")' .shopify/logs/*.json.
--jsonUse app dev --json for a stream of dev output messages. For structured Function records, print one JSON object per line with jq -c . .shopify/logs/*.json. Function run records use the same fields as the earlier app logs --json output.
Multiple --store flagsapp dev connects to one store per session. Run it against each store in turn. Logs from every store go to the same directory, and each record includes storeName.

In network access records, payload uses snake_case keys instead of the camelCase keys in the earlier app logs --json output. For example, update payload.httpRequest lookups to payload.http_request.

app dev installs your local build on the store as the app's dev preview. This preview replaces the installed app version, or another developer's preview, until you run app dev clean. To leave a shared store unchanged, run app dev against your own dev store.

app dev clean doesn't remove .shopify/logs. Saved files can include logs from earlier sessions.

Rename SHOPIFY_APP_AUTOMATION_TOKEN or SHOPIFY_CLI_PARTNERS_TOKEN to SHOPIFY_SERVICE_ACCOUNT_TOKEN in your scripts and CI configuration, keeping the same token value. The old variables remain supported but are deprecated.

Unset both old variables before setting SHOPIFY_SERVICE_ACCOUNT_TOKEN. Shopify CLI rejects environments that set the new variable alongside either old variable.


Anchor to Step 4: Handle outcomes and failuresStep 4: Handle outcomes and failures

For finite commands, check the process exit code as well as the result. A nonzero exit can still include useful validation or partial-result data:

OutcomeJSON behaviorExit behavior
Completed success, no-op, skip, or declined confirmationA result object, with status and changed where applicable.Zero.
Validation that fails the selected blocking policyA completed report with valid: false and issues.Nonzero.
Partially completed requested workA result retaining completed items and failure details.Nonzero.
Failed single operation, setup, authentication, or transportOne fatal error document, such as {"error": {"type": "abort", "message": "Authentication failed."}}.Nonzero.

Fatal error types are abort, bug, and external. Read domain details under error.details. Use a stable code when the error supplies one, and handle its absence. Replace checks for legacy Boolean error values or root status: "failed" single-operation errors with checks for the error object.

For the affected theme commands, an explicit --environment returns one environments array in request order. Each item contains its environment and either result or error. Handle every item, including failures and cancellations. The command exits nonzero when any requested environment fails. For example:

Environment batch

{
"environments": [
{
"environment": "staging",
"result": {"themes": []}
},
{
"environment": "production",
"error": {"type": "abort", "message": "Authentication failed."}
}
]
}

Without an explicit --environment, read the command's ordinary result object.


Anchor to Step 5: Verify your scripts and update production automationStep 5: Verify your scripts and update production automation

Inspect each affected command's schema from the installed version. For example:

terminal

shopify theme list --json-schema

For finite commands, the schema includes Result, Error, and Event definitions. Result and fatal error documents use stdout, while events use stderr. Match your parser to the installed command's result schema. For app dev, use the streaming and session-file schemas described in Step 3.

Run your scripts against the saved cases from your earlier version. Check successful and empty results, cancellations, validation failures, partial work, environment batches, and file output. Adding a new --json mode is separate from changing an existing JSON contract, so migrate the outputs your scripts already consume.

If your scripts fail after the upgrade, then reinstall the latest 4.x release and restore your 4.x-compatible scripts while you finish the migration. For a global npm installation, use npm install -g @shopify/cli@4.

After your scripts pass verification, update explicit CLI versions in CI workflows and release your script changes together with the CLI version change.



Was this page helpful?