Building With Medusa
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.
- Skill ID
- medusajs/medusa-agent-skills/building-with-medusa
- Publisher
- medusajs
- Repository
- medusa-agent-skills
- Installs
- 0
- Files
- 14
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
medusajs/medusa-agent-skills/building-with-medusaInstalls these files- SKILL.md
- reference/api-routes.md
- reference/authentication.md
- reference/custom-modules.md
- reference/data-models.md
- reference/error-handling.md
- reference/frontend-integration.md
- reference/module-links.md
- reference/querying-data.md
- reference/scheduled-jobs.md
- reference/subscribers-and-events.md
- reference/troubleshooting.md
- reference/workflow-hooks.md
- reference/workflows.md
What this skill tells the agent
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
More from medusajs
Use this skill in a project
Open any RiverX project, search the Skills panel for medusajs/medusa-agent-skills/building-with-medusa, and install it in one click.
