5,189,650 AI resources indexedWorking toward the world’s largest AI resource index.

Medusa v2 Custom Modules

Build custom Medusa v2 modules — DML data models, services extending MedusaService, loaders, module links, and container registration. Use when creating custom modules.

Installable skillMITBy OrcaQubitsUpdated Oct 30, 2026
INTENDED FOROpenClawInstall in a listed agent.

instructions.md

---
name: medusa-modules-b1e2ade217bb
description: >
  Build custom Medusa v2 modules — DML data models, services extending
  MedusaService, loaders, module links, and container registration. Use when
  creating custom modules.
---

# Medusa v2 Custom Modules

## Before writing code

**Fetch live docs**:
1. Fetch `https://docs.medusajs.com/learn/fundamentals/modules` for module overview
2. Web-search `site:docs.medusajs.com DML data model reference` for model property types
3. Web-search `site:docs.medusajs.com MedusaService methods` for base service API
4. Web-search `site:docs.medusajs.com module links` for linking modules together
5. Web-search `site:docs.medusajs.com module container registration` for dependency injection

## Module Concept

A module is a self-contained package of functionality in Medusa v2:
- Encapsulates data models, services, and business logic
- Registered in `medusa-config.ts` under the `modules` array
- Accessed from workflows, API routes, and subscribers via the dependency container
- Modules communicate through links, not direct imports

## Module Directory Structure

| 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 Data Models

### Property Types

| 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 Types

| 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 |

### Model Definition Skeleton

```typescript
// 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
})
```

## Service Pattern

Every module exposes a service that extends `MedusaService`:

```typescript
// 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
```

### Inherited MedusaService Methods

| 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`).

## Module Definition Export

```typescript
// 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,
})
```

## Registration in medusa-config.ts

```typescript
// Inside modules array
// Fetch live docs for module registration options
{ resolve: "./src/modules/my-module" }
```

## Module Links

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 |

### Link Definition Skeleton

```typescript
// 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

Loaders run when the module initializes (server startup):
- Seed default data
- Register event listeners
- Validate configuration
- Set up external connections

## Container Resolution

Modules register their service in the dependency injection container:
- Resolved by module key: `container.resolve("my-module")`
- Available in workflows, API routes, subscribers, and other services
- Never import a module's service directly -- always resolve from the container

## Best Practices

- One module per bounded context -- keep modules focused and cohesive
- Use DML models exclusively -- never write raw SQL or use Mikro-ORM directly
- Extend `MedusaService` for CRUD -- only add custom methods for non-standard logic
- Use module links to connect to core entities -- never modify core module tables
- Run `npx medusa db:generate` after every model change to create migrations
- Export a constant for your module key (e.g., `MY_MODULE`) and reuse it everywhere

## Common Patterns

| 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.

Discuss this resource

Platform guidance

Imported from the listed AgentSkill.sh category. Complete supplied package files and notices are retained. Required external tools and credentials are not installed. No bundled code was executed during import. Individual agent task behavior has not been tested.