> medusa
Build headless e-commerce backends with Medusa.js. Use when a user asks to build an online store backend, create a headless e-commerce platform, set up product management and checkout, build a custom storefront, add payment processing to an e-commerce app, manage inventory and orders, or replace Shopify with an open-source alternative. Covers products, carts, orders, payments (Stripe), shipping, plugins, and Next.js storefront integration.
curl "https://skillshub.wtf/TerminalSkills/skills/medusa?format=md"Medusa
Overview
Medusa is an open-source headless e-commerce engine (Node.js + PostgreSQL). It provides a complete backend for products, carts, orders, payments, shipping, and customers — exposed via REST and GraphQL APIs. Think of it as the open-source alternative to Shopify's backend, with full control over customization. This skill covers setup, product management, custom API routes, payment integration (Stripe), and connecting a Next.js storefront.
Instructions
Step 1: Project Setup
# Create new Medusa project
npx create-medusa-app@latest my-store
# This scaffolds: backend (Medusa server) + admin dashboard + storefront (Next.js)
# Or install backend only
npx create-medusa-app@latest my-store --skip-db --no-browser
cd my-store
# Configure database
# .env
DATABASE_URL=postgresql://user:pass@localhost:5432/medusa_store
REDIS_URL=redis://localhost:6379
# Run migrations and seed
npx medusa db:migrate
npx medusa seed --seed-file=data/seed.json
# Start development server
npx medusa develop
# API: http://localhost:9000
# Admin: http://localhost:7001
Step 2: Product Management
// src/api/routes/admin/custom-products.ts — Custom product creation endpoint
// Medusa's admin API handles CRUD, but custom routes extend it
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework"
import { createProductsWorkflow } from "@medusajs/medusa/core-flows"
export async function POST(req: MedusaRequest, res: MedusaResponse) {
const { result } = await createProductsWorkflow(req.scope).run({
input: {
products: [{
title: req.body.title,
description: req.body.description,
status: "published",
options: [
{ title: "Size", values: ["S", "M", "L", "XL"] },
{ title: "Color", values: ["Black", "White", "Navy"] },
],
variants: [
{
title: "Small Black",
sku: "TSHIRT-S-BLK",
prices: [{ amount: 2999, currency_code: "usd" }],
options: { Size: "S", Color: "Black" },
manage_inventory: true,
inventory_quantity: 100,
},
],
images: [{ url: "https://example.com/product.jpg" }],
categories: [{ id: "cat_tshirts" }],
}],
},
})
res.json({ product: result })
}
# REST API examples — Product operations
# List products (public storefront API)
curl http://localhost:9000/store/products
# Get single product
curl http://localhost:9000/store/products/prod_01ABC
# Admin: create product
curl -X POST http://localhost:9000/admin/products \
-H 'Authorization: Bearer admin_token' \
-H 'Content-Type: application/json' \
-d '{"title": "Classic T-Shirt", "status": "published"}'
Step 3: Cart and Checkout Flow
// lib/storefront-client.ts — Client-side cart operations for Next.js storefront
// This is the typical checkout flow: create cart → add items → add shipping → complete
const API_URL = process.env.NEXT_PUBLIC_MEDUSA_URL || "http://localhost:9000"
export async function createCart() {
const res = await fetch(`${API_URL}/store/carts`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ region_id: "reg_us" }),
})
return res.json() // { cart: { id: "cart_01ABC", items: [], total: 0 } }
}
export async function addToCart(cartId: string, variantId: string, quantity: number) {
const res = await fetch(`${API_URL}/store/carts/${cartId}/line-items`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ variant_id: variantId, quantity }),
})
return res.json()
}
export async function completeCheckout(cartId: string) {
// Add customer email
await fetch(`${API_URL}/store/carts/${cartId}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "customer@example.com" }),
})
// Select shipping option
await fetch(`${API_URL}/store/carts/${cartId}/shipping-methods`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ option_id: "so_standard" }),
})
// Initialize payment (Stripe)
await fetch(`${API_URL}/store/carts/${cartId}/payment-sessions`, {
method: "POST",
})
// Complete order
const res = await fetch(`${API_URL}/store/carts/${cartId}/complete`, {
method: "POST",
})
return res.json() // { type: "order", data: { id: "order_01ABC", ... } }
}
Step 4: Payment Integration (Stripe)
# Install Stripe payment plugin
npm install @medusajs/payment-stripe
// medusa-config.ts — Configure Stripe payment provider
import { defineConfig } from "@medusajs/framework"
export default defineConfig({
projectConfig: {
databaseUrl: process.env.DATABASE_URL,
redisUrl: process.env.REDIS_URL,
},
modules: [
{
resolve: "@medusajs/payment",
options: {
providers: [{
resolve: "@medusajs/payment-stripe",
options: {
apiKey: process.env.STRIPE_SECRET_KEY,
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,
},
}],
},
},
],
})
Step 5: Custom API Routes
// src/api/routes/store/custom-search.ts — Custom storefront endpoint
// Extend Medusa's API with business-specific logic
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework"
export async function GET(req: MedusaRequest, res: MedusaResponse) {
const query = req.query.q as string
const productService = req.scope.resolve("product")
const [products, count] = await productService.listAndCount(
{ q: query, status: "published" },
{ take: 20, relations: ["variants", "images"] }
)
res.json({ products, count })
}
Step 6: Subscribers and Events
// src/subscribers/order-placed.ts — React to events (send email, update inventory)
import type { SubscriberArgs, SubscriberConfig } from "@medusajs/framework"
export default async function orderPlacedHandler({ event, container }: SubscriberArgs) {
/**
* Triggered when an order is placed. Use for:
* - Sending confirmation emails
* - Notifying warehouse
* - Updating external systems (ERP, CRM)
*/
const order = event.data
const notificationService = container.resolve("notification")
await notificationService.send("order-confirmation", {
to: order.email,
data: {
order_id: order.id,
items: order.items,
total: order.total,
},
})
}
export const config: SubscriberConfig = {
event: "order.placed",
}
Examples
Example 1: Launch a headless e-commerce store with Next.js frontend
User prompt: "I want to build an online clothing store. Open-source backend, custom Next.js frontend, Stripe payments. I need product variants (size, color), inventory tracking, and a proper checkout flow."
The agent will:
- Scaffold a Medusa project with
create-medusa-app. - Configure PostgreSQL, Redis, and Stripe payment plugin.
- Create product data model with size/color variants and inventory.
- Build Next.js storefront pages: product listing, product detail, cart, checkout.
- Set up order confirmation emails via subscribers.
Example 2: Migrate from Shopify to a self-hosted solution
User prompt: "We're paying $300/month for Shopify Plus. Migrate our 500 products and order history to a self-hosted Medusa backend."
The agent will:
- Export products and orders from Shopify via their Admin API.
- Transform the data to Medusa's format (handle variants, images, metadata).
- Write a migration script that imports products and historical orders.
- Set up equivalent payment and shipping configurations.
Guidelines
- Medusa requires PostgreSQL and Redis — both must be running before starting the server. Use Docker Compose to manage all three services together.
- The admin dashboard (port 7001) is separate from the storefront API (port 9000). Keep the admin behind authentication and network restrictions in production.
- Use Medusa's workflow system for complex operations (multi-step processes like checkout) — it provides automatic rollback on failure.
- For storefronts, use Medusa's official Next.js starter as a base rather than building from scratch — it handles cart state, checkout flow, and API integration.
- Medusa's plugin ecosystem covers payments (Stripe, PayPal), shipping (FedEx, DHL), notifications (SendGrid, Twilio), and search (Meilisearch, Algolia). Check the plugin registry before building custom integrations.
> related_skills --same-repo
> zustand
You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.
> zoho
Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.
> zod
You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.
> zipkin
Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.