Agent skill
shopify
Shopify app and storefront development. Use when writing, reviewing, or scaffolding Shopify apps (Remix/React Router), Hydrogen storefronts, theme app extensions, checkout UI extensions, Shopify Functions, or any code that touches Shopify APIs (Admin GraphQL, Storefront, App Bridge, Polaris). Triggers on shopify.app.toml, @shopify/* imports, Polaris components, Shopify CLI commands, Hydrogen/Oxygen, metafields/metaobjects, webhooks, or any Shopify development task.
Install this agent skill to your Project
npx add-skill https://github.com/JoaquinCampo/Skills/tree/main/shopify
SKILL.md
Shopify Development (2026)
Comprehensive guide for building Shopify apps, extensions, Hydrogen storefronts, and integrations using current best practices.
DevMCP Server
Shopify provides an official MCP server for AI-assisted development. If not already configured:
# Claude Code
claude mcp add --transport stdio shopify-dev-mcp -- npx -y @shopify/dev-mcp@latest
The DevMCP server provides tools to search Shopify docs, explore API schemas (Admin GraphQL, Storefront, Functions, Liquid, Polaris, POS UI Extensions), and get up-to-date answers. Use it for API field lookups and schema exploration.
Stack & Tooling
| Layer | Current (2026) |
|---|---|
| App framework | React Router (formerly Remix) via @shopify/shopify-app-react-router |
| Scaffold | shopify app init → React Router template |
| CLI | @shopify/cli — init, dev, deploy, generate extension |
| UI (embedded apps) | Polaris Web Components (not Polaris React — deprecated) |
| UI (extensions) | Polaris Web Components + Preact (not React) — 64KB bundle limit |
| App Bridge | CDN v4 — https://cdn.shopify.com/shopifycloud/app-bridge.js |
| APIs | Admin GraphQL (primary), Storefront GraphQL, Functions API |
| Custom data | Metafields + Metaobjects via TOML or GraphQL |
| Headless | Hydrogen + Oxygen (React Router v7, Vite, edge rendering) |
| Functions | Wasm — Rust (recommended) or JavaScript (Javy) |
| Config | shopify.app.toml — single source of truth |
Critical:
- REST Admin API is legacy since October 1, 2024. As of April 1, 2025, all new public apps must use GraphQL Admin API exclusively.
- Shopify Scripts: no editing/publishing after April 15, 2026; all scripts stop executing June 30, 2026. Migrate to Functions now.
- Polaris React (
@shopify/polaris) is deprecated (maintenance mode only). Use Polaris Web Components. - UI Extensions (checkout, admin, POS) must use Preact (not React) for API 2025-10+. 64KB bundle size limit enforced at deploy.
Scaffolding
shopify app init # Interactive — choose React Router template
shopify app dev # Local dev with tunnel + hot reload
shopify app generate extension # Add extensions (checkout UI, functions, theme, admin, POS)
shopify app deploy # Deploy app version (config + all extensions)
Directory Structure (React Router template)
my-app/
├── shopify.app.toml # App config, scopes, webhooks, metaobjects
├── app/
│ ├── entry.server.tsx # Server entry
│ ├── root.tsx # Root layout
│ ├── routes/
│ │ ├── app.tsx # Authenticated layout (App Bridge + Polaris)
│ │ ├── app._index.tsx # App home page
│ │ └── webhooks.tsx # Webhook handler
│ └── shopify.server.ts # shopifyApp() config — auth, session storage
├── extensions/ # All extensions live here
│ ├── checkout-ui/
│ ├── theme-extension/
│ └── my-function/
├── prisma/
│ └── schema.prisma # Session table (required)
└── package.json
Authentication & Sessions
- App Bridge v4 (CDN) automatically handles session tokens — no manual JWT fetch needed. The manual setup guide is for legacy App Bridge 2.0 only.
- Embedded apps use session tokens (JWT, 1-minute lifetime). Third-party cookies are blocked by browsers.
@shopify/shopify-app-react-router(recommended) or@shopify/shopify-app-remix(v4, still works) handle OAuth + token exchange automatically.- Session storage: Prisma adapter (
@shopify/shopify-app-session-storage-prisma) — the Session table is required. - Use
authenticate.admin(request)in loaders/actions for authenticated Admin API access. - Use
authenticate.public.checkout(request)for checkout extension requests. - Never expose Admin API tokens in client-side code.
- Use offline access tokens for bulk operations and webhooks (online tokens expire in 24h).
// app/shopify.server.ts
import { shopifyApp } from "@shopify/shopify-app-react-router";
import { PrismaSessionStorage } from "@shopify/shopify-app-session-storage-prisma";
import prisma from "./db.server";
const shopify = shopifyApp({
sessionStorage: new PrismaSessionStorage(prisma),
// API key, secret, scopes, and app URL are read from
// shopify.app.toml + environment variables automatically
});
export default shopify;
export const authenticate = shopify.authenticate;
// In a route loader:
export async function loader({ request }: LoaderFunctionArgs) {
const { admin } = await authenticate.admin(request);
const response = await admin.graphql(`{ shop { name } }`);
const { data } = await response.json();
return { shopName: data.shop.name };
}
Migration note: If on
@shopify/shopify-app-remix, migrate to@shopify/shopify-app-react-router— see migration guide.
Polaris Web Components (NOT Polaris React)
Polaris React is deprecated. Use Polaris Web Components — framework-agnostic custom HTML elements.
Setup
<head>
<meta name="shopify-api-key" content="%SHOPIFY_API_KEY%" />
<script src="https://cdn.shopify.com/shopifycloud/app-bridge.js"></script>
<script src="https://cdn.shopify.com/shopifycloud/polaris.js"></script>
</head>
Usage in React (App Home)
function ProductForm() {
const [name, setName] = useState("");
return (
<s-page title="New Product">
<s-layout>
<s-layout-section>
<s-card>
<s-form-layout>
<s-text-field
label="Product name"
value={name}
onInput={(e) => setName(e.currentTarget.value)}
required
/>
<s-button variant="primary" type="submit">Save</s-button>
</s-form-layout>
</s-card>
</s-layout-section>
</s-layout>
</s-page>
);
}
Key Patterns
- Elements are prefixed with
s-(e.g.,s-card,s-button,s-badge,s-data-table). - Use
onInputfor real-time updates,onChangefor on-blur/enter validation. - All form values are strings — parse numbers/booleans yourself.
toneapplies semantic color (critical,success,info);variantsets visual weight (primary,secondary).- Links with
target="auto"auto-detect internal (_self) vs external (_blank). - Do not apply custom CSS to Polaris components — they have built-in design system styling.
Navigation (App Bridge)
// Handle Shopify navigation events in Remix/React Router
useEffect(() => {
const handler = (event) => {
const href = event.target.getAttribute("href");
if (href) navigate(href);
};
document.addEventListener("shopify:navigate", handler);
return () => document.removeEventListener("shopify:navigate", handler);
}, [navigate]);
Use <s-navigation-menu> for sidebar nav. Use shopify.navigate() for programmatic navigation. Never use <a> tags or redirect from react-router in embedded apps — use Link from react-router or the redirect helper from authenticate.admin.
Admin GraphQL API
Query Patterns
// Simple query
const response = await admin.graphql(`
query {
products(first: 10) {
edges {
node { id title handle }
}
}
}
`);
// Mutation with variables
const response = await admin.graphql(`
mutation createProduct($input: ProductInput!) {
productCreate(input: $input) {
product { id title }
userErrors { field message }
}
}
`, { variables: { input: { title: "New Product" } } });
// Always check userErrors
const { data } = await response.json();
if (data.productCreate.userErrors.length > 0) {
throw new Error(data.productCreate.userErrors[0].message);
}
Rate Limiting
- Admin GraphQL uses calculated query cost (cost points, not request count).
- Complex queries with nested connections cost more points.
- Use
cursor-based pagination for large datasets. - For bulk data: use bulk operations (
bulkOperationRunQuery/bulkOperationRunMutation) — up to 5 concurrent queries and 5 concurrent mutations per shop in API 2026-01+ (previously 1 each). - Use offline access tokens for bulk operations (online tokens expire before completion).
API Version
Always pin to a stable version (e.g., 2026-01). Set in shopify.app.toml:
[webhooks]
api_version = "2026-01"
Storefront API
- For all customer-facing data: products, collections, cart, checkout.
- No rate limits on request count — scales for buyer traffic surges.
- Requires Storefront access token (public, safe for client-side).
- Use in Hydrogen storefronts, mobile apps, or headless frontends.
Metafields & Metaobjects
When to Use Which
| Use Case | Tool |
|---|---|
| Add custom field to existing resource (product, order, customer) | Metafield |
| Create standalone reusable structured data | Metaobject |
| App-internal data model | Metaobject with $app: prefix in TOML |
App-Owned Metafields (TOML)
# shopify.app.toml — auto-created on `shopify app dev`
[[metaobjects]]
type = "$app:qrcode"
[metaobjects.access]
admin = "merchant_read_write"
storefront = "public_read"
[[metaobjects.fields]]
key = "title"
type = "single_line_text_field"
name = "Title"
required = true
[[metaobjects.fields]]
key = "product"
type = "product_reference"
name = "Product"
Merchant-Owned Metafields (GraphQL)
mutation {
metafieldDefinitionCreate(definition: {
name: "Warranty Info"
namespace: "custom" # NOT $app — merchant-owned
key: "warranty_info"
type: "multi_line_text_field"
ownerType: PRODUCT
access: { storefront: PUBLIC_READ }
}) {
createdDefinition { name namespace key }
}
}
$appnamespace = app-owned (read-only in admin by default).customor other namespaces = merchant-owned.- Use TOML for app-owned; GraphQL for merchant-owned.
Webhooks
Configuration (TOML)
[webhooks]
api_version = "2026-01"
[[webhooks.subscriptions]]
topics = ["orders/create", "products/update"]
uri = "/webhooks"
[[webhooks.subscriptions]]
compliance_topics = ["customers/data_request", "customers/redact", "shop/redact"]
uri = "https://app.example.com/webhooks"
Mandatory Compliance (Required for App Store)
Every public app must handle these three webhooks:
customers/data_request— respond with customer data you storecustomers/redact— delete customer personal datashop/redact— delete all shop data after uninstall
Validate HMAC on every webhook. Return 401 for invalid HMAC, 200 for valid.
GraphQL Subscriptions
mutation {
webhookSubscriptionCreate(
topic: ORDERS_CREATE
webhookSubscription: {
callbackUrl: "https://app.example.com/webhooks"
format: JSON
}
) {
webhookSubscription { id }
userErrors { field message }
}
}
Shopify Functions (Wasm)
Extend Shopify backend logic (discounts, validation, delivery, payment customization) as sandboxed WebAssembly modules.
Language Choice
- Rust: 3x faster than JS. Required for public apps with complex logic or high line-item counts. Stays within instruction count limits.
- JavaScript (via Javy → Wasm): Viable for prototyping and simple logic (<5ms realistic cases). Lower barrier to entry.
Execution Order in Checkout
- Cart Transform → 2. Discount (cart lines) → 3. Fulfillment/Order Routing → 4. Delivery Customization → 5. Discount (delivery) → 6. Payment Customization → 7. Cart Validation
Scaffold & Build
shopify app generate extension # Choose function type
shopify app function schema # Regenerate GraphQL schema
shopify app function run # Test locally
Structure
extensions/my-discount/
├── shopify.extension.toml # Extension config (target, API version)
├── src/
│ ├── run.graphql # Input query — what data the function receives
│ └── run.rs (or run.js) # Function logic
├── schema.graphql # Generated API schema
└── Cargo.toml (or package.json)
Performance: Functions run during checkout — delays block purchases. Minimize instruction count. Avoid unnecessary data in run.graphql.
Extensions
Types
| Extension | Purpose |
|---|---|
theme_app_extension |
Liquid blocks/snippets in Online Store themes |
checkout_ui_extension |
Custom UI at checkout extension points |
admin_action |
Dropdown actions on admin resource pages |
admin_block |
Embedded blocks on admin resource pages |
pos_ui_extension |
POS interface extensions |
| Functions | Backend logic (discounts, delivery, validation, payments) |
Theme App Extensions
Required for all new App Store apps (replaces manual theme code editing).
extensions/theme-extension/
├── shopify.extension.toml
├── blocks/
│ └── rating.liquid
├── snippets/
├── assets/
└── locales/
Checkout UI Extensions
20+ extension points (e.g., Checkout::Dynamic::Render). Use Polaris Web Components. Keep lightweight — mobile-first.
Critical: React is deprecated for UI extensions as of API 2025-10. Must use Preact for any API version 2025-10+. Vanilla React + ui-react package exceeds the 64KB bundle limit.
# shopify.extension.toml
api_version = "2026-01"
[[extensions]]
name = "my-checkout-ext"
handle = "my-checkout-ext"
type = "ui_extension"
// package.json dependencies for UI extensions
{
"dependencies": {
"preact": "^10.10.x",
"@preact/signals": "^2.3.x",
"@shopify/ui-extensions": "2026.1.x"
}
}
// tsconfig.json for Preact JSX
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact"
}
}
Hydrogen & Oxygen (Headless)
Stack
- Hydrogen: React framework (React Router v7 + Vite) with Storefront API utilities, streaming SSR, granular caching.
- Oxygen: Shopify's edge runtime (based on Cloudflare workerd). Multiple preview environments. CI/CD via GitHub.
- Vite-first: Legacy Remix compiler no longer supported — must use Vite.
Key Patterns
// Caching — be explicit
const { storefront } = await context.storefront.query(PRODUCT_QUERY, {
cache: CacheLong(), // or CacheShort(), CacheNone(), CacheCustom()
});
// Streaming for performance
export default function Product() {
return (
<Suspense fallback={<ProductSkeleton />}>
<Await resolve={recommendedProducts}>
{(products) => <ProductGrid products={products} />}
</Await>
</Suspense>
);
}
AI Integration (2026)
Hydrogen on Oxygen supports Storefront MCP — build AI agents into storefronts for personalized recommendations and checkout guidance using real-time Storefront API data.
App Store Submission Checklist
- GraphQL only — no REST API calls
- Session tokens — no cookie-based auth
- Mandatory compliance webhooks — all three implemented and HMAC-validated
- Theme app extensions — no manual theme code injection
- Polaris Web Components — consistent admin UI
- Performance — must not reduce Lighthouse score by >10 points
- Privacy — GDPR/CCPA compliant, data handling documented
- Credentials — provide valid test credentials with full feature access
- Screencast — complete walkthrough of setup + functionality
- No Shopify trademarks in app icon/banner/screenshots
- Review timeline: 7–14 days. Statuses: Draft → Submitted → Reviewed → Published.
Common Pitfalls
- Using
<a>or bareredirect()in embedded apps (breaks iframe). UseLinkfromreact-routeror the redirect helper fromauthenticate.admin. - Using Polaris React (
@shopify/polaris) instead of Polaris Web Components — deprecated, maintenance-only. - Using React in UI extensions targeting API 2025-10+ — must use Preact (64KB bundle limit).
- Exposing Admin API tokens client-side.
- Using REST API in new apps (legacy since Oct 2024; blocked for new public apps since April 2025).
- Not validating webhook HMAC.
- Using online access tokens for bulk operations (they expire in 24h).
- Heavy checkout extensions that slow mobile performance.
- Not handling
userErrorsin GraphQL mutations. - Missing the
$app:namespace prefix for app-owned metaobjects. - Forgetting to run
shopify app function schemaafter changing API version. - Using
@shopify/shopify-app-remixfor new projects instead of@shopify/shopify-app-react-router.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
sparse-retrieval-eval
Evaluate sparse retrieval models on standard IR benchmarks (BEIR, MIRACL, mMARCO). Covers all IR metrics (nDCG@k, Recall@k, MAP, MRR), dataset loading, sparse corpus encoding to CSR matrices, IDF-weighted retrieval, caching, and result interpretation. Triggers on: evaluate retrieval, BEIR benchmark, nDCG, recall@k, sparse retrieval evaluation, MIRACL evaluation, information retrieval metrics, IR evaluation, search quality metrics.
wandb-plot
Download and generate plots from Weights & Biases runs. Use when you need to: - List projects you have access to - List runs in a W&B project - Inspect available metrics for a run - Download existing plot images from a run - Generate line plots from metric history (loss, accuracy, etc.)
go
Go engineering best practices and idioms. This skill should be used when writing, reviewing, or refactoring Go code. Triggers on any .go file work, Go module operations, go test, go build, go run, go vet, go generate, or when the user mentions Go, golang, goroutines, channels, context, Go interfaces, Go error handling, Go testing, or Go concurrency. ALWAYS use this skill when Go code is involved, even for simple functions.
fastapi
FastAPI best practices and conventions. Use when working with FastAPI APIs and Pydantic models for them. Keeps FastAPI code clean and up to date with the latest features and patterns, updated with new versions. Write new code or refactor and update old code.
kvpress
kvpress (NVIDIA) KV-cache compression for HuggingFace LLMs. Use when: kvpress imports, compression_ratio, press(model) context managers, StreamingLLMPress, SnapKVPress, ExpectedAttentionPress, TOVAPress, KnormPress, KV-cache eviction, token pruning during generation, or attention sink methods.
plantuml
Create, edit, and render PlantUML diagrams. Triggers on: architecture diagrams, flowcharts, sequence diagrams, data models, state machines, visual documentation.
Didn't find tool you were looking for?