building-with-medusa
medusajs/medusa-agent-skills
Essential patterns and rules for Medusa backend development—modules, workflows, API routes, and data models.
What is building-with-medusa?
Comprehensive guide for building Medusa backend features including custom modules, workflows, API routes, and data models. Load this skill for any backend development task to access architectural patterns, type-safety rules, and critical best practices that prevent common implementation mistakes.
- Enforces critical architecture flow: Module → Workflow → API Route → Frontend
- Provides type-safety rules for request schemas, authenticated routes, and Zod v4 usage
- Defines business logic placement rules (workflows for mutations, validation, ownership checks)
- Documents data access patterns including price formatting and cross-module querying with query.graph() and query.index()
- Specifies file organization conventions for workflows, steps, middleware, and module links
- Includes workflow composition constraints (no async/await, no arrow functions, no conditionals)
How to install building-with-medusa
npx skills add https://github.com/medusajs/medusa-agent-skills --skill building-with-medusa- Medusa v2.14.0 or later (for Zod v4 compatibility)
- Node.js and npm/yarn for skill installation
- Understanding of TypeScript and async patterns
How to use building-with-medusa
- 1.Install the skill using: npx skills add https://github.com/medusajs/medusa-agent-skills --skill building-with-medusa
- 2.Load this skill automatically when planning, researching, or implementing any Medusa backend features
- 3.Before implementing specific components, load the relevant reference file: custom-modules.md for modules, workflows.md for workflows, api-routes.md for routes, module-links.md for links, querying-data.md for queries, or authentication.md for auth
- 4.Follow the critical architecture flow: Module (data models) → Workflow (business logic) → API Route (HTTP interface) → Frontend
- 5.Check the rule categories by priority and verify your implementation against the common mistakes checklist before coding
Use cases
- Creating custom modules with data models and CRUD operations
- Implementing workflows for mutations with rollback and business logic
- Building API routes (store or admin) with proper validation and authentication
- Defining module links to maintain isolation between entities
- Querying data across modules using query.graph() for simple retrieval or query.index() for filtering linked data
- Backend developers building Medusa applications
- Full-stack developers implementing custom features and business logic
- Architects designing module structure and data relationships
- Teams migrating to Medusa or extending existing backends
building-with-medusa FAQ
Load this skill for ANY backend development task: creating modules, implementing workflows, building API routes, defining module links, writing business logic, querying data, or implementing authentication. It's REQUIRED for all Medusa backend work in planning, implementation, and exploration modes.
Always follow: Module (data models + CRUD) → Workflow (business logic + mutations) → API Route (HTTP interface) → Frontend. Never bypass layers by calling module services directly from routes, and use workflows for ALL mutations.
The three most critical mistakes are: (1) calling module services directly from API routes instead of using workflows, (2) using PUT/PATCH methods instead of GET/POST/DELETE, and (3) placing business logic in routes instead of workflow steps. Also avoid setting explicit `fields` with `req.queryConfig` and forgetting to use `AuthenticatedMedusaRequest` for protected routes.
Use `query.graph()` for simple cross-module retrieval with dot notation. Use `query.index()` (Index Module) when you need to filter by properties of linked data models in separate modules. Never use JavaScript `.filter()` on linked data—use database filters instead.
Prices are stored as-is in Medusa (49.99 is stored as 49.99, NOT in cents). Never multiply by 100 when saving or divide by 100 when displaying. This applies to all price-related operations.
Full instructions (SKILL.md)
Source of truth, from medusajs/medusa-agent-skills.
name: building-with-medusa description: Load automatically when planning, researching, or implementing ANY Medusa backend features (custom modules, API routes, workflows, data models, module links, business logic). REQUIRED for all Medusa backend work in ALL modes (planning, implementation, exploration). Contains architectural patterns, best practices, and critical rules that MCP servers don't provide.
Medusa Backend Development
Comprehensive backend development guide for Medusa applications. Contains patterns across 6 categories covering architecture, type safety, business logic placement, and common pitfalls.
When to Apply
Load this skill for ANY backend development task, including:
- Creating or modifying custom modules and data models
- Implementing workflows for mutations
- Building API routes (store or admin)
- Defining module links between entities
- Writing business logic or validation
- Querying data across modules
- Implementing authentication/authorization
Also load these skills when:
- building-admin-dashboard-customizations: Building admin UI (widgets, pages, forms)
- building-storefronts: Calling backend API routes from storefronts (SDK integration)
CRITICAL: Load Reference Files When Needed
The quick reference below is NOT sufficient for implementation. You MUST load relevant reference files before writing code for that component.
Load these references based on what you're implementing:
- Creating a module? → MUST load
reference/custom-modules.mdfirst - Creating workflows? → MUST load
reference/workflows.mdfirst - Creating API routes? → MUST load
reference/api-routes.mdfirst - Creating module links? → MUST load
reference/module-links.mdfirst - Querying data? → MUST load
reference/querying-data.mdfirst - Adding authentication? → MUST load
reference/authentication.mdfirst
Minimum requirement: Load at least 1-2 reference files relevant to your specific task before implementing.
Critical Architecture Pattern
ALWAYS follow this flow - never bypass layers:
Module (data models + CRUD operations)
↓ used by
Workflow (business logic + mutations with rollback)
↓ executed by
API Route (HTTP interface, validation middleware)
↓ called by
Frontend (admin dashboard/storefront via SDK)
Key conventions:
- Only GET, POST, DELETE methods (never PUT/PATCH)
- Workflows are required for ALL mutations
- Business logic belongs in workflow steps, NOT routes
- Query with
query.graph()for cross-module data retrieval - Query with
query.index()(Index Module) for filtering across separate modules with links - Module links maintain isolation between modules
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Architecture Violations | CRITICAL | arch- |
| 2 | Type Safety | CRITICAL | type- |
| 3 | Business Logic Placement | HIGH | logic- |
| 4 | Import & Code Organization | HIGH | import- |
| 5 | Data Access Patterns | MEDIUM (includes CRITICAL price rule) | data- |
| 6 | File Organization | MEDIUM | file- |
Quick Reference
1. Architecture Violations (CRITICAL)
arch-workflow-required- Use workflows for ALL mutations, never call module services from routesarch-layer-bypass- Never bypass layers (route → service without workflow)arch-http-methods- Use only GET, POST, DELETE (never PUT/PATCH)arch-module-isolation- Use module links, not direct cross-module service callsarch-query-config-fields- Don't set explicitfieldswhen usingreq.queryConfig
2. Type Safety (CRITICAL)
type-request-schema- Pass Zod inferred type toMedusaRequest<T>when usingreq.validatedBodytype-authenticated-request- UseAuthenticatedMedusaRequestfor protected routes (notMedusaRequest)type-export-schema- Export both Zod schema AND inferred type from middlewarestype-linkable-auto- Never add.linkable()to data models (automatically added)type-module-name-camelcase- Module names MUST be camelCase, never use dashes (causes runtime errors)
3. Business Logic Placement (HIGH)
logic-workflow-validation- Put business validation in workflow steps, not API routeslogic-ownership-checks- Validate ownership/permissions in workflows, not routeslogic-module-service- Keep modules simple (CRUD only), put logic in workflows
4. Import & Code Organization (HIGH)
import-top-level- Import workflows/modules at file top, never useawait import()in route bodyimport-static-only- Use static imports for all dependenciesimport-no-dynamic-routes- Dynamic imports add overhead and break type checkingimport-zod-framework- Import Zod from@medusajs/framework/zod, never fromzoddirectly. Medusa is on Zod v4 (since v2.14.0): usez.email()/z.url()/z.uuid()instead ofz.string().email()etc.,.extend(other.shape)instead of.merge(other),z.strictObject()/z.looseObject()instead of.strict()/.passthrough(),z.enum(MyEnum)instead ofz.nativeEnum(), andz.record(z.string(), value)instead ofz.record(value)
5. Data Access Patterns (MEDIUM)
data-price-format- CRITICAL: Prices are stored as-is in Medusa (49.99 stored as 49.99, NOT in cents). Never multiply by 100 when saving or divide by 100 when displayingdata-query-method- Usequery.graph()for retrieving data; usequery.index()(Index Module) for filtering across linked modulesdata-query-graph- Usequery.graph()for cross-module queries with dot notation (without cross-module filtering)data-query-index- Usequery.index()when filtering by properties of linked data models in separate modulesdata-list-and-count- UselistAndCountfor single-module paginated queriesdata-linked-filtering-query.graph()can't filter by linked module fields - usequery.index()or query from that entity directlydata-no-js-filter- Don't use JavaScript.filter()on linked data - use database filters (query.index()or query the entity)data-same-module-ok- Can filter by same-module relations withquery.graph()(e.g., product.variants)data-auth-middleware- Trustauthenticatemiddleware, don't manually checkreq.auth_context
6. File Organization (MEDIUM)
file-workflow-steps- Recommended: Create steps insrc/workflows/steps/[name].tsfile-workflow-composition- Composition functions insrc/workflows/[name].tsfile-middleware-exports- Export schemas and types from middleware filesfile-links-directory- Define module links insrc/links/[name].ts
Workflow Composition Rules
The workflow function has critical constraints:
// ✅ CORRECT
const myWorkflow = createWorkflow(
"name",
function (input) { // Regular function, not async, not arrow
const result = myStep(input) // No await
return new WorkflowResponse(result)
}
)
// ❌ WRONG
const myWorkflow = createWorkflow(
"name",
async (input) => { // ❌ No async, no arrow functions
const result = await myStep(input) // ❌ No await
if (input.condition) { /* ... */ } // ❌ No conditionals
return new WorkflowResponse(result)
}
)
Constraints:
- No async/await (runs at load time)
- No arrow functions (use
function) - No conditionals/ternaries (use
when()) - No variable manipulation (use
transform()) - No date creation (use
transform()) - Multiple step calls need
.config({ name: "unique-name" })to avoid conflicts
Common Mistakes Checklist
Before implementing, verify you're NOT doing these:
Architecture:
- Calling module services directly from API routes
- Using PUT or PATCH methods
- Bypassing workflows for mutations
- Setting
fieldsexplicitly withreq.queryConfig - Skipping migrations after creating module links
Type Safety:
- Forgetting
MedusaRequest<SchemaType>type argument - Using
MedusaRequestinstead ofAuthenticatedMedusaRequestfor protected routes - Not exporting Zod inferred type from middlewares
- Adding
.linkable()to data models - Using dashes in module names (must be camelCase)
Business Logic:
- Validating business rules in API routes
- Checking ownership in routes instead of workflows
- Manually checking
req.auth_context?.actor_idwhen middleware already applied
Imports:
- Using
await import()in route handler bodies - Dynamic imports for workflows or modules
Data Access:
- CRITICAL: Multiplying prices by 100 when saving or dividing by 100 when displaying (prices are stored as-is: $49.99 = 49.99)
- Filtering by linked module fields with
query.graph()(usequery.index()or query from other side instead) - Using JavaScript
.filter()on linked data (usequery.index()or query the linked entity directly) - Not using
query.graph()for cross-module data retrieval - Using
query.graph()when you need to filter across separate modules (usequery.index()instead)
Validating Implementation
CRITICAL: Always run the build command after completing implementation to catch type errors and runtime issues.
When to Validate
- After implementing any new feature
- After making changes to modules, workflows, or API routes
- Before marking tasks as complete
- Proactively, without waiting for the user to ask
How to Run Build
Detect the package manager and run the appropriate command:
npm run build # or pnpm build / yarn build
Handling Build Errors
If the build fails:
- Read the error messages carefully
- Fix type errors, import issues, and syntax errors
- Run the build again to verify the fix
- Do NOT mark implementation as complete until build succeeds
Common build errors:
- Missing imports or exports
- Type mismatches (e.g., missing
MedusaRequest<T>type argument) - Incorrect workflow composition (async functions, conditionals)
Linting
Since Medusa v2.16.0, projects can install @medusajs/eslint-plugin, which catches violations of Medusa conventions (API routes, subscribers, scheduled jobs, admin customizations, module patterns) that a type check won't.
- If the project has an
eslint.config.*with@medusajs/eslint-plugin,medusa buildandmedusa developrun linting by default and fail on lint errors. Fix lint errors rather than passing--no-lint. - Run linting explicitly with
npx medusa lint(supports--fixand--quiet). Run it after implementing a feature, alongside the build. - If the project has no ESLint config, suggest adding it (
@medusajs/eslint-plugin,eslint, andjitias dev dependencies, then aneslint.config.tsexportingdefineConfig([...medusa.configs.recommended])) — but don't add it unprompted.
Next Steps - Testing Your Implementation
After successfully implementing a feature, always provide these next steps to the user:
1. Start the Development Server
If the server isn't already running, start it:
npm run dev # or pnpm dev / yarn dev
2. Access the Admin Dashboard
Open your browser and navigate to:
- Admin Dashboard: http://localhost:9000/app
Log in with your admin credentials to test any admin-related features.
3. Test API Routes
If you implemented custom API routes, list them for the user to test:
Admin Routes (require authentication):
POST http://localhost:9000/admin/[your-route]- Description of what it doesGET http://localhost:9000/admin/[your-route]- Description of what it does
Store Routes (public or customer-authenticated):
POST http://localhost:9000/store/[your-route]- Description of what it doesGET http://localhost:9000/store/[your-route]- Description of what it does
Testing with cURL example:
# Admin route (requires authentication)
curl -X POST http://localhost:9000/admin/reviews/123/approve \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
--cookie "connect.sid=YOUR_SESSION_COOKIE"
# Store route
curl -X POST http://localhost:9000/store/reviews \
-H "Content-Type: application/json" \
-d '{"product_id": "prod_123", "rating": 5, "comment": "Great product!"}'
4. Additional Testing Steps
Depending on what was implemented, mention:
- Workflows: Test mutation operations and verify rollback on errors
- Subscribers: Trigger events and check logs for subscriber execution
- Scheduled jobs: Wait for job execution or check logs for cron output
Format for Presenting Next Steps
Always present next steps in a clear, actionable format after implementation:
## Implementation Complete
The [feature name] has been successfully implemented. Here's how to test it:
### Start the Development Server
[server start command based on package manager]
### Access the Admin Dashboard
Open http://localhost:9000/app in your browser
### Test the API Routes
I've added the following routes:
**Admin Routes:**
- POST /admin/[route] - [description]
- GET /admin/[route] - [description]
**Store Routes:**
- POST /store/[route] - [description]
### What to Test
1. [Specific test case 1]
2. [Specific test case 2]
3. [Specific test case 3]
How to Use
For detailed patterns and examples, load reference files:
reference/custom-modules.md - Creating modules with data models
reference/workflows.md - Workflow creation and step patterns
reference/api-routes.md - API route structure and validation
reference/module-links.md - Linking entities across modules
reference/querying-data.md - Query patterns and filtering rules
reference/authentication.md - Protecting routes and accessing users
reference/error-handling.md - MedusaError types and patterns
reference/scheduled-jobs.md - Cron jobs and periodic tasks
reference/subscribers-and-events.md - Event handling
reference/troubleshooting.md - Common errors and solutions
Each reference file contains:
- Step-by-step implementation checklists
- Correct vs incorrect code examples
- TypeScript patterns and type safety
- Common pitfalls and solutions
When to Use This Skill vs MedusaDocs MCP Server
⚠️ CRITICAL: This skill should be consulted FIRST for planning and implementation.
Use this skill for (PRIMARY SOURCE):
- Planning - Understanding how to structure Medusa backend features
- Architecture - Module → Workflow → API Route patterns
- Best practices - Correct vs incorrect code patterns
- Critical rules - What NOT to do (common mistakes and anti-patterns)
- Implementation patterns - Step-by-step guides with checklists
Use MedusaDocs MCP server for (SECONDARY SOURCE):
- Specific method signatures after you know which method to use
- Built-in module configuration options
- Official type definitions
- Framework-level configuration details
Why skills come first:
- Skills contain opinionated guidance and anti-patterns MCP doesn't have
- Skills show architectural patterns needed for planning
- MCP is reference material; skills are prescriptive guidance
Integration with Frontend Applications
⚠️ CRITICAL: Frontend applications MUST use the Medusa JS SDK for ALL API requests
When building features that span backend and frontend:
For Admin Dashboard:
- Backend (this skill): Module → Workflow → API Route
- Frontend: Load
building-admin-dashboard-customizationsskill - Connection:
- Built-in endpoints: Use existing SDK methods (
sdk.admin.product.list()) - Custom API routes: Use
sdk.client.fetch("/admin/my-route") - NEVER use regular fetch() - missing auth headers will cause errors
- Built-in endpoints: Use existing SDK methods (
For Storefronts:
- Backend (this skill): Module → Workflow → API Route
- Frontend: Load
building-storefrontsskill - Connection:
- Built-in endpoints: Use existing SDK methods (
sdk.store.product.list()) - Custom API routes: Use
sdk.client.fetch("/store/my-route") - NEVER use regular fetch() - missing publishable API key will cause errors
- Built-in endpoints: Use existing SDK methods (
Why the SDK is required:
- Store routes need
x-publishable-api-keyheader - Admin routes need
Authorizationand session headers - SDK handles all required headers automatically
- Regular fetch() without headers → authentication/authorization errors
See respective frontend skills for complete integration patterns.
Related skills
More from medusajs/medusa-agent-skills and the wider catalog.

db-generate
Generate database migrations for Medusa modules with a single command.

db-migrate
Execute Medusa database migrations to apply pending schema changes.

learning-medusa
Interactive step-by-step tutorial for learning Medusa development by building a brands feature.

new-user
Create a new admin user in Medusa with email and password.

storefront-best-practices
Framework-agnostic ecommerce storefront patterns, component design, and Medusa backend integration guidance.

eastmoney_financial_data
本 Skill 基于东方财富权威数据库及最新行情底层数据构建,支持通过自然语言查询行情类数据(股票、行业、板块、指数、基金、债券的实时行情、主力资金流向、估值等)、财务类数据(上市公司基本信息、财务指标、高管信息、主营业务等)、关系与经营类数据(关联关系、企业经营数据)。避免模型基于过时知识回答金融数据问题,提供权威及时的金融数据。