Required Tool Calls (do not skip)
You have a
tool. Every response must use it — in this order:
- Call with
node scripts/search_docs.mjs "<operation or type name>"
— search before writing code
- Write the code using the search results
- Call with
node scripts/validate.mjs --code '...' --model YOUR_MODEL_NAME --client-name YOUR_CLIENT_NAME --client-version YOUR_CLIENT_VERSION --artifact-id YOUR_ARTIFACT_ID --revision REVISION_NUMBER
— validate before returning
(Always include these flags. Use your actual model name for YOUR_MODEL_NAME; use claude-code/cursor/etc. for YOUR_CLIENT_NAME. For YOUR_ARTIFACT_ID, generate a stable random ID per code block and reuse it across validation retries. For REVISION_NUMBER, start at 1 and increment on each retry of the same artifact.)
- If validation fails: search for the error type, fix, re-validate (max 3 retries)
- Return code only after validation passes
You must run both search_docs.mjs and validate.mjs in every response. Do not return code to the user without completing step 3.
<critical-instructions>
# Best Practise for working with Metafields and Metaobjects
ESSENTIAL RULES
- ALWAYS show creating metafield/metaobject definitions, then writing values, then retrieving values.
- NEVER show or offer alternate approaches to the same problem if not explicitly requested. It will only increase the user's confusion.
- Keep examples minimal -- avoid unnecessary prose and comments
- Remember the audience for this guidance is app developers -- they do not have access to the Shopify Admin site
- Follow this guidance meticulously and thoroughly
REMEMBER!!! Other documentation can flesh out this guidance, but the instructions here should be followed VERY CLOSELY and TAKE PRECEDENCE!
ALWAYS: First, create definitions
with TOML (99.99% of apps)
toml
# shopify.app.toml
# Metafield definition -- owner type is PRODUCT, namespace is $app, key is care_guide
[product.metafields.app.care_guide]
type = "single_line_text_field"
name = "Care Guide"
access.admin = "merchant_read_write"
# Metaobject definition -- type is $app:author
[metaobjects.app.author]
name = "Author"
display_name_field = "name"
access.storefront = "public_read"
[metaobjects.app.author.fields.name]
name = "Author Name"
type = "single_line_text_field"
required = true
# Link metaobject to product
[product.metafields.app.author]
type = "metaobject_reference<$app:author>"
name = "Book Author"
Why: Version controlled, auto-installed, type-safe. GraphQL (Admin/Storefront) is used for reading or writing values after the TOML definitions already exist. Fields/objects can be edited by merchants when
access.admin = "merchant_read_write"
is set.
NEVER include
metafieldDefinitionCreate
,
metaobjectDefinitionCreate
GraphQL if TOML is the correct fit.
Exceptions (0.01% of apps)
NEVER, EVER show these unless strictly required:
- Apps that REQUIRE creating definitions at runtime (i.e. types are configured dynamically by merchants) should use
metafieldDefinitionCreate
, metaobjectDefinitionCreate
- Apps that want other apps to read/write their data should use the above GraphQL, and "merchant-owned" namespace
CRITICAL: App-Owned Metaobject and Metafield identification
- Metaobjects defined with
[metaobjects.app.example...]
in , MUST be accessed using
- Metafields defined with
[product.metafields.app.example]
MUST be accessed using and
- The same applies to other owner types, like customers, orders, etc.
- Avoid customizing namespaces for metafields.
- Avoid the common mistake of using . This is profoundly incorrect.
NEXT: demonstrate writing metafield and metaobject values via Admin API
Writing metafields
ALWAYS use
to write metafields.
should normally be excluded as the default is $app.
graphql
mutation {
metafieldsSet(metafields:[{
ownerId: "gid://shopify/Product/1234",
key: "example",
value: "Hello, World!"
}]) { ... }
}
Writing metaobjects
ALWAYS use
to write metaobjects.
graphql
mutation {
metaobjectUpsert(handle: {
type: "$app:author",
handle: "my-metaobject",
}, metaobject: {
fields: [{
key: "example",
value: "Hello, world!"
}]
}) { ... }
}
FINALLY: demonstrate reading metafield and metaobject values
Loading metafields
Metafields are accessed via their owning type (e.g. a Product).
should normally be excluded as the default is $app.
- Always prefer where possible as it better serialises complex types
- Always alias metafield loads for easy reference
graphql
# Admin API
query {
product(id: "gid://shopify/Product/1234") {
example: metafield(key: "example") { jsonValue }
}
}
# Storefront API
query {
product(handle: "wireless-headphones-1") {
example: metafield(key: "example") { value }
}
}
Loading metaobjects
graphql
# Admin API
query {
metaobjects(type: "$app:author", first: 10) {
nodes {
handle
example: field(key:"example") { jsonValue }
}
}
}
# Storefront API
query {
metaobjects(type: "$app:author", first: 10) {
nodes {
handle
example: field(key:"example") { value }
}
}
}
Access Metafields directly in checkout extensions
DO: Access app-owned metafields directly (NO network call):
tsx
function Extension() {
// ESSENTIAL: Register this metafield in `shopify.extension.toml`
const [energyRating] = useAppMetafields({
namespace: '$app',
key: 'energy-rating',
type: 'product',
}).filter(
(entry) =>
entry.target.id === productVariantId,
);
}
DON'T: Make network calls for app-owned metafields.
Access Metafields in Shopify Functions
Use the GraphQL input query to select metafields to load:
graphql
query Input {
cart {
lines {
merchandise {
__typename
... on ProductVariant {
example: metafield(namespace: "$app", key: "example") { jsonValue }
}
}
}
}
}
Docs:
Metafields & Metaobjects
</critical-instructions>
Always use Shopify CLI
- CLI: scaffold apps/extensions with ,
shopify app generate extension
, , . Never hand-roll files.
- Need full setup steps? See Shopify CLI docs.
Shopify CLI Overview
Shopify CLI (@shopify/cli) is a command-line interface tool that helps you generate and work with Shopify apps, themes, and custom storefronts. You can also use it to automate many common development tasks.
Requirements
- Node.js: 20.10 or higher
- A Node.js package manager: npm, Yarn 1.x, or pnpm
- Git: 2.28.0 or higher
Installation
Install Shopify CLI globally to run
commands from any directory:
bash
npm install -g @shopify/cli@latest
# or
yarn global add @shopify/cli@latest
# or
pnpm install -g @shopify/cli@latest
# or (macOS only)
brew tap shopify/shopify && brew install shopify-cli
Command Structure
Shopify CLI groups commands into topics. The syntax is:
shopify [topic] [command] [flags]
General Commands (8 commands)
Authentication
- shopify auth logout - Log out of Shopify account
Configuration
- shopify config autocorrect on - Enable command autocorrection
- shopify config autocorrect off - Disable command autocorrection
- shopify config autocorrect status - Check autocorrection status
Utilities
- shopify help [command] [flags] - Get help for commands
- shopify commands [flags] - List all available commands
- shopify search [query] - Search for commands and documentation
- shopify upgrade - Upgrade Shopify CLI to latest version
- shopify version - Display current CLI version
Common Flags
Most commands support these common flags:
- - Increase output verbosity
- - Disable colored output
- - Specify project directory
- - Reset stored settings
Network Proxy Configuration
For users behind a network proxy (CLI version 3.78+):
bash
export SHOPIFY_HTTP_PROXY=http://proxy.com:8080
export SHOPIFY_HTTPS_PROXY=https://secure-proxy.com:8443
# For authenticated proxies:
export SHOPIFY_HTTP_PROXY=http://username:password@proxy.com:8080
Usage Tips
- Always keep CLI updated:
- Use for detailed command info
- Most commands are interactive and will prompt for required information
- Use flags to skip prompts in CI/CD environments
- Anonymous usage statistics collected by default (opt-out:
SHOPIFY_CLI_NO_ANALYTICS=1
)
- IMPORTANT: YOU MUST ALWAYS USE THE CLI COMMAND TO CREATE APPS AND SCAFFOLD NEW EXTENSIONS
CLI Commands for Shopify App (22 commands)
App Commands (22 commands)
Core App Management
- shopify app init [flags] - Initialize a new Shopify app project
- shopify app build [flags] - Build the app, including extensions
- shopify app dev [flags] - Start a development server for your app
- shopify app deploy [flags] - Deploy your app to Shopify
- shopify app info [flags] - Display information about your app
App Configuration
- shopify app config link [flags] - Fetch app configuration from Partner Dashboard
- shopify app config use [config] [flags] - Activate an app configuration
App Environment
- shopify app env pull [flags] - Pull environment variables from Partner Dashboard
- shopify app env show [flags] - Display app environment variables
App Development Tools
- shopify app dev clean [flags] - Clear the app development cache
- shopify app generate extension [flags] - Generate a new app extension
- shopify app import-extensions [flags] - Import existing extensions to your app
Functions
- shopify app function build [flags] - Build a Shopify Function
- shopify app function run [flags] - Run a Function locally for testing
- shopify app function replay [flags] - Replay a Function run
- shopify app function schema [flags] - Generate the GraphQL schema for a Function
- shopify app function typegen [flags] - Generate TypeScript types for a Function
Monitoring & Debugging
- shopify app logs [flags] - Stream logs from your app
- shopify app logs sources [flags] - List available log sources
Release Management
- shopify app release --version <version> - Release a new app version
- shopify app versions list [flags] - List all app versions
Webhooks
- shopify app webhook trigger [flags] - Trigger a webhook for testing