Help us improve
Share bugs, ideas, or general feedback.
From medusa-commerce
Provides patterns for Next.js 15 storefronts with Medusa v2: App Router structure, server/client components, JS SDK integration, data fetching, caching, server actions.
npx claudepluginhub orcaqubits/agentic-commerce-skills-plugins --plugin medusa-commerceHow this skill is triggered — by the user, by Claude, or both
Slash command
/medusa-commerce:nextjs-patternsThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
**Fetch live docs**:
Builds Medusa v2 headless storefronts with Next.js 15 App Router, JS SDK, TanStack Query, server components, product pages, cart, and checkout flows.
Guides Medusa storefronts: JS SDK for API calls, React Query for data fetching/mutations, custom routes, error handling, cache invalidation.
Provides best practices, UI/UX patterns, and guidance for ecommerce storefronts: checkout, cart, products, navigation, homepage. Integrates Medusa backend; framework-agnostic (Next.js, React, Vue).
Share bugs, ideas, or general feedback.
Fetch live docs:
site:docs.medusajs.com storefront nextjs for Medusa storefront guideshttps://docs.medusajs.com/resources/references/js-sdk for JS SDK method referencesite:nextjs.org docs app router for latest Next.js 15 App Router conventionssite:docs.medusajs.com nextjs starter storefront for starter template patternssite:docs.medusajs.com publishable api key storefront for API authentication setupsrc/app/
├── layout.tsx — Root layout (providers, SDK)
├── page.tsx — Home page
├── (main)/products/ — Product listing + [handle]/
├── (main)/cart/ — Cart, checkout, account
└── lib/medusa.ts — SDK client initialization
| Concept | File Convention | Purpose in Medusa Storefront |
|---|---|---|
| Layout | layout.tsx | Wrap pages with providers, header, footer |
| Page | page.tsx | Route entry point (server component default) |
| Loading | loading.tsx | Streaming fallback UI |
| Error | error.tsx | Error boundary per route segment |
| Not Found | not-found.tsx | 404 page for invalid product handles, etc. |
| Route Groups | (group)/ | Organize without affecting URL |
| Dynamic Routes | [param]/ | Product handles, category slugs |
| Parallel Routes | @slot/ | Simultaneous layout regions |
| Criterion | Server Component | Client Component |
|---|---|---|
| Data fetching | Fetch from Medusa API directly | Use Tanstack Query hooks |
| SEO | Full HTML rendered on server | Not indexed by crawlers |
| Interactivity | No event handlers | onClick, onChange, etc. |
| State | No useState/useEffect | Full React hooks |
| Examples | Product listing, product detail, categories | Cart actions, quantity selector, search |
| Directive | None (default) | "use client" at top |
ProductPage (server)
├── ProductInfo (server) — Title, description, price
├── ProductImages (server) — Image gallery markup
├── AddToCart (client) — "use client", quantity, button
└── RelatedProducts (server) — Fetched server-side
| Option | Purpose | Example Value |
|---|---|---|
baseUrl | Medusa server URL | http://localhost:9000 |
publishableKey | Store API authentication | From admin dashboard |
auth.type | Authentication strategy | "session" or "jwt" |
| Domain | Method Pattern | Component Type |
|---|---|---|
| Products | sdk.store.product.list() | Server (listing) |
| Products | sdk.store.product.retrieve(id) | Server (detail) |
| Cart | sdk.store.cart.create() | Client (interaction) |
| Cart | sdk.store.cart.addLineItem() | Client (interaction) |
| Cart | sdk.store.cart.update() | Client (interaction) |
| Checkout | sdk.store.cart.addShippingMethod() | Client (checkout flow) |
| Customer | sdk.auth.login() | Client (auth form) |
| Customer | sdk.store.customer.retrieve() | Server or Client |
| Regions | sdk.store.region.list() | Server (layout) |
| Collections | sdk.store.collection.list() | Server (navigation) |
Call the Medusa SDK directly in server components — no hooks needed:
// Fetch live docs for server-side SDK
// usage and async component patterns
| Pattern | Use Case |
|---|---|
Direct await sdk.store.* | Server components with async data |
generateMetadata() | Dynamic SEO metadata from product data |
generateStaticParams() | ISR/SSG for product and category pages |
| Hook / Concern | Purpose |
|---|---|
useQuery | Read data with caching and automatic refetch |
useMutation | Write operations (add to cart, login) |
useQueryClient | Invalidate cache after mutations |
| Query keys | Use consistent keys like ["cart", cartId] |
| Optimistic updates | Update cart UI immediately, rollback on error |
| Prefetching | Prefetch product data on hover for navigation |
| Layer | Scope | Medusa Use Case |
|---|---|---|
| Request Memoization | Per-request dedup | Multiple components fetching same product |
| Data Cache | Cross-request | Product catalog data (revalidate periodically) |
| Full Route Cache | Entire page | Static product pages (ISR) |
| Router Cache | Client-side | Navigation between cached pages |
| Strategy | Method | Use Case |
|---|---|---|
| Time-based | revalidate: 60 (seconds) | Product listings, category pages |
| On-demand | revalidatePath() / revalidateTag() | After admin product update |
| No cache | cache: "no-store" | Cart, checkout, customer data |
| Data Type | Cache Strategy | Reasoning |
|---|---|---|
| Products | revalidate: 60-300 | Changes infrequently |
| Collections | revalidate: 300-3600 | Rarely changes |
| Cart | no-store | User-specific, changes constantly |
| Customer | no-store | Private, per-session |
| Regions | revalidate: 3600 | Almost never changes |
| Prices | revalidate: 60 | May change with promotions |
Server actions handle form submissions and mutations from server components:
// Fetch live docs for Next.js server actions
// with Medusa SDK mutation patterns
"use server"
| Use Case | Action Pattern |
|---|---|
| Add to cart | Server action calling sdk.store.cart.addLineItem() |
| Update quantity | Server action with revalidatePath |
| Apply discount | Server action calling sdk.store.cart.update() |
| Customer login | Server action wrapping sdk.auth.login() |
Use server actions for simple form mutations. Use API routes when external systems need to call your storefront.
| Variable | Purpose | Where Used |
|---|---|---|
NEXT_PUBLIC_MEDUSA_BACKEND_URL | Medusa server URL | Client + Server |
NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY | Store API key | Client + Server |
REVALIDATE_WINDOW | Default ISR revalidation time | Server only |
"use client" only for interactive elements; split pages into server (data) and client (interaction) sub-componentsloading.tsx for streaming with Suspense boundaries; prefetch data for likely navigation targets; optimize images with next/image and Medusa media URLsFetch the Medusa Next.js storefront documentation and JS SDK reference for exact method signatures, query key conventions, and starter template patterns before implementing.