Help us improve
Share bugs, ideas, or general feedback.
From medusa-commerce
Builds custom Medusa v2 modules with DML data models, services extending MedusaService, loaders, module links, and container registration. Use when extending Medusa.
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:medusa-modulesThis 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**:
Guides Medusa backend development for custom modules, API routes, workflows, data models, module links, and business logic with architecture patterns, best practices, and rules.
Builds Node.js backends for Medusa v2 using Express middleware chains, MikroORM entity patterns, PostgreSQL pooling, async patterns, error handling, and logging.
Guides developers step-by-step through building a custom brands feature in Medusa, teaching modules, workflows, API routes, module links, hooks, and admin UI customization.
Share bugs, ideas, or general feedback.
Fetch live docs:
https://docs.medusajs.com/learn/fundamentals/modules for module overviewsite:docs.medusajs.com DML data model reference for model property typessite:docs.medusajs.com MedusaService methods for base service APIsite:docs.medusajs.com module links for linking modules togethersite:docs.medusajs.com module container registration for dependency injectionA module is a self-contained package of functionality in Medusa v2:
medusa-config.ts under the modules array| File | Purpose |
|---|---|
src/modules/my-module/models/my-entity.ts | DML data model |
src/modules/my-module/service.ts | Service extending MedusaService |
src/modules/my-module/loaders/seed.ts | Optional loader (runs on startup) |
src/modules/my-module/migrations/ | Auto-generated by CLI |
src/modules/my-module/index.ts | Module definition export |
| DML Type | Database Column | Notes |
|---|---|---|
model.id() | Primary key UUID | Auto-generated |
model.text() | text / varchar | String fields |
model.number() | integer | Numeric fields |
model.bigNumber() | numeric | Precise decimals (prices) |
model.boolean() | boolean | True/false |
model.dateTime() | timestamptz | Date/time values |
model.json() | jsonb | Arbitrary JSON |
model.enum() | enum | Constrained values |
model.array() | array | Array of primitives |
| Relationship | DML Method | Description |
|---|---|---|
| Has One | model.hasOne() | One-to-one owned |
| Has Many | model.hasMany() | One-to-many owned |
| Belongs To | model.belongsTo() | Inverse of hasOne/hasMany |
| Many to Many | model.manyToMany() | Junction table auto-created |
// src/modules/my-module/models/my-entity.ts
// Fetch live docs for current DML model API
import { model } from "@medusajs/framework/utils"
const MyEntity = model.define("my_entity", {
id: model.id(), name: model.text(),
// Fetch live docs for property options and relationships
})
Every module exposes a service that extends MedusaService:
// src/modules/my-module/service.ts
// Fetch live docs for MedusaService generic signature
import { MedusaService } from "@medusajs/framework/utils"
import MyEntity from "./models/my-entity"
class MyModuleService extends MedusaService({ MyEntity }) {}
export default MyModuleService // Add custom methods as needed
| Method Pattern | Purpose |
|---|---|
create<Entity>(data) | Create one or many records |
update<Entity>(data) | Update records by selector or ID |
delete<Entity>(ids) | Soft-delete records |
retrieve<Entity>(id, config) | Retrieve single record by ID |
list<Entity>(filters, config) | List with filters, pagination, relations |
softRestore<Entity>(ids) | Restore soft-deleted records |
The method names are auto-generated from the model name (e.g., createMyEntity, listMyEntities).
// src/modules/my-module/index.ts
// Fetch live docs for Module definition shape
import { Module } from "@medusajs/framework/utils"
import MyModuleService from "./service"
export const MY_MODULE = Module("my-module", {
service: MyModuleService,
})
// Inside modules array
// Fetch live docs for module registration options
{ resolve: "./src/modules/my-module" }
Links connect data models across different modules without coupling:
| Link Type | Purpose |
|---|---|
| One-to-one link | Connect a custom entity to a core entity (e.g., product) |
| One-to-many link | One core entity linked to many custom entities |
| List link | Bidirectional many-to-many between modules |
// src/links/product-my-entity.ts
// Fetch live docs for defineLink API
import { defineLink } from "@medusajs/framework/utils"
import ProductModule from "@medusajs/medusa/product"
import { MY_MODULE } from "../modules/my-module"
Links are queried using the query utility from the Medusa container, not through direct service calls.
Loaders run when the module initializes (server startup):
Modules register their service in the dependency injection container:
container.resolve("my-module")MedusaService for CRUD -- only add custom methods for non-standard logicnpx medusa db:generate after every model change to create migrationsMY_MODULE) and reuse it everywhere| Pattern | When to Use |
|---|---|
| Custom module + link to Product | Adding metadata/features to products |
| Custom module + link to Order | Order-related extensions (loyalty, tracking) |
| Standalone module | Independent domain (CMS, analytics, reviews) |
| Module with loader | Pre-seeding data or external service setup |
Fetch the Medusa module documentation for exact DML property options, MedusaService generics, and link definition patterns before implementing.