You can build a working Shopify app with Claude Code in an afternoon: install Shopify CLI 3.x and Claude Code, scaffold the official Remix template, connect the Shopify Dev MCP server so Claude reads live API schema, then prompt it to build your admin block and webhook handler. This guide walks the full path, from empty folder to deployed app.
Why this stack works
Shopify app development in 2026 is unusually friendly to AI coding agents, for one specific reason: the official tooling is opinionated. The Remix app template makes the auth, routing, and session decisions for you. The CLI scaffolds extensions with correct config. And the Dev MCP server lets an agent check its GraphQL against the real schema instead of guessing.
That last part matters more than it sounds. Shopify versions its Admin API quarterly, REST product endpoints are legacy, and training data goes stale fast. An agent grounded in live schema writes queries that pass on the first run. An agent working from memory writes queries that fail with Field 'x' doesn't exist on type 'y' and burns your afternoon.
Here is the toolchain:
| Tool | Install | Role |
|---|---|---|
| Node.js 20+ | nvm or nodejs.org | Runtime for the CLI and the app |
| Shopify CLI 3.x | npm install -g @shopify/cli | Scaffold, run, and deploy the app |
| Claude Code | npm install -g @anthropic-ai/claude-code | Agentic coding in your terminal |
| Shopify Dev MCP | npx -y @shopify/dev-mcp@latest | Live schema and docs access for Claude |
| Partner account | partners.shopify.com | App registration and development stores |
If you have never used Claude Code before, the Claude Code developer guide covers the core workflow. And if you are still choosing an AI tool, Claude Code vs GitHub Copilot in 2026 compares them for exactly this kind of project work.
Step 1: Install the CLI and Claude Code
# Shopify CLI (3.x)
npm install -g @shopify/cli@latest
shopify version
# Claude Code
npm install -g @anthropic-ai/claude-code
claude --version
Anthropic also ships a native installer (curl -fsSL https://claude.ai/install.sh | bash) if you prefer to keep it out of your global npm packages. Sign in with claude on first run; it works with both Claude subscriptions and API billing.
Step 2: Partner account and a development store
Create a free account at shopify.com/partners, then create a development store from the Partner Dashboard. Choose the option to start with test data so you get products, collections, and customers to build against instead of an empty catalog.
Development stores are free and never charge real payments, which makes them the right sandbox for app work. If you also want a real storefront of your own to run the app against live traffic later, create a separate Shopify store for that; keep development and production worlds apart from day one.
Step 3: Scaffold the Remix app template
shopify app init
The CLI asks for a name and a template. Pick Remix, the official template Shopify maintains. It gives you embedded auth with session tokens, Prisma-backed session storage, a webhook route pattern, and an extensions/ directory wired into the deploy pipeline.
Start the dev loop:
cd restock-radar
shopify app dev
shopify app dev creates the app in your Partner organization on first run, tunnels your local server to a public URL, and prints an install link. Open it, install the app on your development store, and you have a live embedded app running from your laptop. Keep this process running in one terminal for the rest of the build; Claude Code runs in a second one.
The generated app talks to the GraphQL Admin API. That is the correct default: REST product endpoints are legacy, and the reasons are covered in Shopify GraphQL vs REST. For auth concepts and rate limits behind what the template abstracts away, see the Shopify Admin API guide.
Step 4: Wire the Shopify Dev MCP server
This is the step most people skip, and it is the highest-value one. From inside your app directory:
claude mcp add --transport stdio shopify-dev-mcp -- npx -y @shopify/dev-mcp@latest
Restart Claude Code and it now has Shopify-specific tools: schema introspection across Admin, Storefront, and Functions APIs, semantic search over shopify.dev, and a validator that checks generated GraphQL code blocks against the real schema. No API key needed; the server runs locally and only reads public developer resources.
The practical effect: instead of pasting documentation into your prompt, you tell Claude to look things up and verify. Hallucinated mutations get caught before they reach your codebase.
Step 5: Prompt patterns that work for Shopify APIs
Generic prompts produce generic code. These patterns produce Shopify code that works:
Anchor to existing files. The template is your style guide. "Follow the pattern in app/routes/app._index.jsx" beats three paragraphs of instructions.
Force schema verification. Tell Claude to introspect and validate before writing GraphQL, every time.
One vertical slice per prompt. A route, an extension, a webhook. Small tasks keep diffs reviewable and failures cheap.
Here is a real prompt in that shape:
Read shopify.app.toml and app/shopify.server.js first.
Task: add a page at /app/restock that lists the 25 product variants
with the lowest inventory. Query the Admin GraphQL API (2026-04) from
the Remix loader, never from the browser.
Rules:
- Before writing any GraphQL, introspect the schema with the
shopify-dev-mcp tools and validate the final query with the
validation tool.
- Follow the existing route conventions in app/routes/.
- No new dependencies without asking me.
- When done, tell me what to click in the dev store to verify.
A CLAUDE.md that pays for itself
Standing rules belong in a CLAUDE.md at the repo root, which Claude Code reads at the start of every session. Here is the one we converge on for Shopify apps:
# CLAUDE.md (excerpt)
## Shopify rules
- Admin API version is 2026-04. GraphQL only; REST product endpoints
are legacy and must not be used.
- Always introspect the schema and validate GraphQL with the
shopify-dev-mcp tools before presenting code.
- Every /app route loader starts with authenticate.admin(request).
- Webhook handlers return a 200 fast and queue slow work.
- Do not modify shopify.server.js or auth routes without flagging it
and explaining why.
## Verification
- After UI changes, tell me exactly what to click in the dev store.
- Run npm run lint and npm test before calling a task done.
Treat this file like a linter config: any time you correct Claude twice for the same mistake, the correction moves here. The rules above encode the specific failure modes from this guide, so a fresh session starts with the judgment a previous session had to learn.
If you are comparing this terminal-first workflow with browser builders like Replit or Lovable, we tested those separately in building a Shopify app with AI app builders; the short version is that the CLI plus Claude Code wins once real Shopify APIs are involved.
Step 6: Build an admin block with Claude
An admin block renders your app's UI directly on a resource page in the Shopify admin, such as the product details page. Generate the extension first so the config is right:
shopify app generate extension
# choose: Admin block
The CLI creates extensions/<name>/ with a TOML file targeting a location in the admin:
api_version = "2026-04"
[[extensions]]
name = "restock-signal"
handle = "restock-signal"
type = "ui_extension"
[[extensions.targeting]]
module = "./src/BlockExtension.jsx"
target = "admin.product-details.block.render"
Admin UI extensions use Preact with Shopify's Polaris web components (the s- prefixed elements), not full React and not Liquid. Now hand the implementation to Claude: "Implement BlockExtension.jsx for the admin.product-details.block.render target. Show the selected product's ID and a placeholder line for reorder data. Use the current admin extension component set; verify component names with the Dev MCP tools." A minimal working block looks like this:
// extensions/restock-signal/src/BlockExtension.jsx
import { render } from "preact";
export default function extension() {
render(<Block />, document.body);
}
function Block() {
const product = shopify.data.selected?.[0];
return (
<s-admin-block heading="Restock signal">
<s-stack direction="block" gap="base">
<s-text>Product: {product?.id ?? "none selected"}</s-text>
<s-text>Reorder velocity will render here.</s-text>
</s-stack>
</s-admin-block>
);
}
With shopify app dev still running, open any product in your development store admin, click "Add block" in the apps section of the page, and pick your extension. Edits hot-reload. This tight loop is where an agent shines: you describe a change, Claude edits, you refresh the product page and judge the result.
Step 7: Add a webhook handler
Webhooks are declared in shopify.app.toml, so subscriptions deploy with your app config instead of being registered imperatively:
[webhooks]
api_version = "2026-04"
[[webhooks.subscriptions]]
topics = ["products/update"]
uri = "/webhooks/products/update"
Then the Remix route. This is a fine Claude task ("add a webhook route for products/update following the existing app/uninstalled handler"), and the result should look close to this:
// app/routes/webhooks.products.update.jsx
import { authenticate } from "../shopify.server";
export const action = async ({ request }) => {
const { shop, topic, payload } = await authenticate.webhook(request);
console.log(`${topic} for ${shop}: product ${payload.id}`);
// Do fast work only. Queue anything slow; Shopify retries
// deliveries that don't get a prompt 2xx response.
return new Response();
};
authenticate.webhook verifies the HMAC signature for you, which is the part hand-rolled handlers most often get wrong. Test without touching the store:
shopify app webhook trigger \
--topic products/update \
--api-version 2026-04 \
--delivery-method http \
--address http://localhost:3000/webhooks/products/update
You should see your log line with a sample payload. Then verify the real path: edit a product title in the dev store and watch the event arrive through the tunnel. Once you move past one topic, read catalog change webhooks for ordering, retries, and debouncing bursts; a bulk admin edit can fire thousands of products/update events in seconds.
Step 8: Deploy
Two things deploy separately. Extensions and app config go to Shopify:
shopify app deploy
That creates a new app version containing your admin block and webhook subscriptions and releases it. Your Remix server is yours to host: Fly.io and Render are the common picks for the template because webhook delivery wants an always-on process rather than a cold-starting function. Set the environment variables the template expects (SHOPIFY_API_KEY, SHOPIFY_API_SECRET, DATABASE_URL), point application_url in shopify.app.toml at the production hostname, and run shopify app deploy again so Shopify knows the new URL.
Swap the template's SQLite session storage for Postgres before real merchants install; SQLite on an ephemeral host loses sessions on every restart.
Troubleshooting the first hour
Three failures account for most stuck sessions, and none of them are Claude's fault:
shopify app dev cannot match your app. Usually a stale link between the local project and the Partner app, often after renaming or switching accounts. shopify app dev --reset re-runs the selection flow and fixes it.
The embedded app renders a blank iframe or bounces to a login loop. You opened the tunneled URL directly in a browser tab, or third-party storage is blocked. Always open the app through the dev store admin, where App Bridge can fetch session tokens.
GraphQL calls return 401 after a restart. The SQLite session database was deleted or regenerated, so the stored access token is gone. Reinstall via the install link that shopify app dev prints and the session recreates itself.
Paste the exact error into Claude before debugging by hand; with the MCP server connected it will usually identify these patterns and point at the right file.
Where Claude Code helps, and where it does not
Honest scorecard from building apps this way:
Strong: template-conformant routes, GraphQL against introspected schema, extension boilerplate, webhook handlers, refactors across the repo, writing tests you asked for.
Weak: knowing which access scopes are genuinely needed (it over-asks; trim them, reviewers check), deciding what runs inline versus in a queue, App Store review requirements, and anything it cannot verify by running code. Claude will also happily "fix" an embedded auth loop by disabling auth if you let it. Review every diff that touches shopify.server.js.
The 2-hour estimate in the steps above is real for the skeleton: scaffold, MCP, one block, one webhook, deployed. A submittable App Store app is more like a week or two, because billing, GDPR webhooks, and review polish are judgment work, not typing work.
Next step
Scaffold the app tonight and give yourself one deliverable: the admin block rendering live data from a loader instead of a placeholder. That single task forces the full loop (prompt, schema introspection, loader query, extension render, dev store verification) and after it, the rest of the app is repetition.