AgentStack
SKILL verified MIT Self-run

Shopify App

skill-mentilead-shopify-app-skill-shopify-app · by mentilead

Production patterns for embedded Shopify apps with React Router v7,

No reviews yet
0 installs
0 views
view→install

Install

$ agentstack add skill-mentilead-shopify-app-skill-shopify-app

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README — it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-mentilead-shopify-app-skill-shopify-app)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
4mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming — see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps — measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Shopify App? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

CRITICAL GOTCHAS (Top 10)

1. Never Use Polaris url Prop for Internal Navigation

// WRONG — breaks out of iframe
Upgrade

// CORRECT — stays in iframe
const navigate = useNavigate();
 navigate('/app/pricing')}>Upgrade

Rule: url prop is only safe for external URLs. Use useNavigate() for internal routes.

2. Never Use NODE_ENV for Billing isTest Flag

// WRONG — always false on Lambda (staging included)
isTest: process.env.NODE_ENV !== 'production'

// CORRECT — detect via Shopify API
isTest: await isDevelopmentStore(admin)

3. useFetcher Data Goes to fetcher.data, Not useActionData()

// WRONG — always undefined when using fetcher
const actionData = useActionData();

// CORRECT — read from fetcher
const fetcher = useFetcher();
const fetcherData = fetcher.data as { ok?: boolean; error?: string } | undefined;

4. useState Doesn't Sync with Loader After Save

// WRONG — state diverges from loader after save
const [brandColor, setBrandColor] = useState(settings.brandColor);

// CORRECT — sync from loader when data changes
const lastSyncRef = useRef(settings.updatedAt);
useEffect(() => {
  if (settings.updatedAt !== lastSyncRef.current) {
    setBrandColor(settings.brandColor);
    lastSyncRef.current = settings.updatedAt;
  }
}, [settings.updatedAt, settings.brandColor]);

5. Parent + Child Loaders Run in Parallel (Billing Race Condition)

// CORRECT — redirect after billing sync to force clean second load
const url = new URL(request.url);
if (url.searchParams.has('charge_id')) {
  url.searchParams.delete('charge_id');
  throw redirect(url.pathname + url.search);
}

6. App Proxy: GET Only, No External CSS/JS

| Constraint | Detail | |-----------|--------| | GET only | Proxy only forwards GET. POST must go directly to the app URL. | | No external CSS/JS | ` and resolve against storefront domain and 404. | | No Tailwind ?inline | Tailwind 4's Vite plugin doesn't process @tailwind for ?inline` imports. | | No client-side hydration | React Router JS bundles don't load through the proxy. |

7. Plus Dev Stores Can't Approve Test Charges

Create a non-Plus (Basic) dev store for billing testing. Plus dev stores show "This feature isn't currently available."

8. Custom Apps Cannot Use Billing API

App must be Public or Unlisted distribution — not Custom.

9. CloudFront Strips Host Header — CSRF Failure

// CDK fix: add x-forwarded-host custom origin header
const apiOrigin = new origins.HttpOrigin(apiDomain, {
  customHeaders: { 'x-forwarded-host': config.domainName },
});

10. shopify app dev --store Flag Ignored with Cached Association

# WRONG — --store flag is ignored
shopify app dev --store different-store.myshopify.com

# CORRECT — reset cached association first
shopify app dev --reset

Quick Reference

shopifyApp() Config Skeleton

const shopify = shopifyApp({
  apiKey: process.env.SHOPIFY_API_KEY,
  apiSecretKey: process.env.SHOPIFY_API_SECRET || '',
  apiVersion: ApiVersion.October25,
  scopes: process.env.SCOPES?.split(','),
  appUrl: process.env.SHOPIFY_APP_URL || '',
  authPathPrefix: '/auth',
  sessionStorage: new DynamoDBSessionStorage(),
  distribution: AppDistribution.AppStore,
  billing: { /* plan definitions */ },
  future: { expiringOfflineAccessTokens: true },
});

Route Naming Conventions

| Pattern | Purpose | URL | |---------|---------|-----| | app.tsx | Layout (nav, Polaris, billing) | — | | app._index.tsx | Dashboard | /app | | app.forms.$id.tsx | Form editor | /app/forms/:id | | proxy.tsx | Public proxy layout | — | | api.submit-application.tsx | POST endpoint | /api/submit-application | | webhooks.app.uninstalled.tsx | Webhook handler | — |

Prefixes: app. = authenticated admin, proxy. = public HMAC-verified, api. = headless, webhooks. = Shopify webhooks.

Layout Route (app.tsx) Pattern

  • Loads Polaris styles, runs authenticate.admin(), syncs billing to DynamoDB
  • Provides `, , wrapping `
  • Includes ErrorBoundary and headers from boundary
  • Uses shouldRevalidate to skip revalidation on POST (prevents flicker)

shouldRevalidate Pattern

export const shouldRevalidate = ({ formMethod, defaultShouldRevalidate }) => {
  if (formMethod === 'POST') return false;
  return defaultShouldRevalidate;
};

ClientOnly Component

export function ClientOnly({ children, fallback = null }: Props) {
  const [mounted, setMounted] = useState(false);
  useEffect(() => { setMounted(true); }, []);
  return mounted ? <>{children} : <>{fallback};
}

SSR Hydration Rule

NEVER use inline event handlers — they cause hydration mismatches in SSR apps. Always use onClick, onChange, etc. via React state and handlers.


Project Structure

your-app/
  app/
    routes/              # File-based routes (app.*, proxy.*, api.*, webhooks.*)
    components/          # React components (ClientOnly, etc.)
    services/            # Business logic (*.server.ts)
      dynamodb/          # keys.ts, mappers.ts
    lib/                 # Core infra (dynamodb.server.ts, config.server.ts)
    lambda-workers/      # SQS handlers (email, export)
    shopify.server.ts    # shopifyApp() config
    lambda.server.ts     # Lambda entry point
  infra/                 # CDK stacks
  tests/                 # Playwright E2E
  extensions/            # Shopify app extensions

Service Conventions

  • All DB access through app/services/*.server.ts
  • First param is always shopDomain (multi-tenant scoping)
  • Keys via app/services/dynamodb/keys.ts
  • .server.ts suffix = tree-shaken from client bundles

Key Environment Variables

| Variable | Source | Description | |----------|--------|-------------| | SHOPIFY_API_KEY | Secrets Manager | App API key | | SHOPIFY_API_SECRET | Secrets Manager | App API secret | | SHOPIFY_APP_URL | SSM | App URL | | DYNAMODB_TABLE | SSM | Table name | | DYNAMODB_ENDPOINT | .env (local) | DynamoDB Local endpoint | | AWS_S3_BUCKET | SSM | Documents bucket | | EMAIL_QUEUE_URL | SSM | SQS email queue URL |


Scope

In scope: Embedded Shopify apps, React Router v7, DynamoDB single-table, Lambda, SQS, CDK, Polaris, App Proxy, Billing API, Webhooks, GDPR compliance.

Out of scope: Liquid theme development, Hydrogen/headless, Checkout UI Extensions, Shopify Functions, POS extensions, Prisma/PostgreSQL.


Companion Tools

Use the official Shopify Dev MCP server alongside this skill for documentation search, GraphQL schema exploration, and Liquid validation. See shopify.dev/docs/apps/build/devmcp.

MCP config (add to your .claude/settings.json or Claude Desktop config):

{
  "mcpServers": {
    "shopify-dev-mcp": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/shopify-dev-mcp"]
    }
  }
}

Orchestrator Pattern

When building a new feature, decompose into layers and build each before moving to the next:

  1. Explore — constraints, architecture, security, integration points (references/feature-exploration.md)
  2. Database — keys, entity design, queries (references/dynamodb-patterns.md)
  3. API — service functions, route loader/action (references/react-router-patterns.md)
  4. UI — Polaris components, state management (references/polaris-ui-patterns.md)

Step 0 runs when planning or analyzing a feature — not during active implementation. Build and test each layer independently. This prevents coupling bugs and makes code review easier.


When to Consult References

| Task | Reference | |------|-----------| | Routing, loaders, actions, fetchers | references/react-router-patterns.md | | DynamoDB keys, queries, transactions | references/dynamodb-patterns.md | | GraphQL API, customers, metafields | references/shopify-api-patterns.md | | Billing flow, plans, trials | references/billing-patterns.md | | App Proxy pages, HMAC, forms | references/app-proxy-patterns.md | | Webhook handlers, GDPR, uninstall | references/webhook-patterns.md | | Lambda cold start, SQS workers | references/lambda-architecture.md | | CDK stacks, CloudFront, monitoring | references/cdk-infrastructure.md | | Polaris UI, design tokens, composition | references/polaris-ui-patterns.md | | Email queuing, suppression, Resend | references/email-patterns.md | | Multi-tenancy, CORS, S3 presigned URLs | references/security-patterns.md | | Playwright, FrameLocator, selectors | references/testing-patterns.md | | Docker, DynamoDB Local, startup | references/local-dev-patterns.md | | Zero-to-production deployment, AWS setup, DNS, CI/CD | references/production-deployment.md | | Planning a new feature, analyzing constraints | references/feature-exploration.md | | File naming, service patterns, env vars, TOML | references/project-conventions.md |

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.