MedusaJS Development Templates
Comprehensive code templates based on official MedusaJS v2 documentation and best practices.
Overview
This collection provides production-ready templates for common MedusaJS development patterns. Each template includes:
- Complete, working code examples
- Inline documentation and comments
- Usage instructions
- Best practices and patterns
- Common variations and extensions
Templates Available
1. module-complete.ts
Complete Custom Module Structure
Includes:
- Multiple data models with various property types
- One-to-many and many-to-many relationships
- Main service extending MedusaService
- Additional custom services
- Module configuration and exports
- Usage examples
Use when: Creating a new custom module with data models and business logic
// Example: Blog Module, Brand Module, Restaurant Module, etc.
2. api-route-complete.ts
Complete REST API Route
Includes:
- GET, POST, PUT, DELETE handlers
- Zod validation schemas
- Middleware configuration (authentication & validation)
- Error handling patterns
- Query integration for related data
- Pagination and filtering
Use when: Creating API endpoints to expose module functionality
// Example: /api/brands, /api/restaurants, /api/reviews
3. workflow-complete.ts
Complete Workflow with Steps
Includes:
- Multiple workflow steps
- Input/output typing
- Compensation functions for rollback
- Data transformation between steps
- Conditional execution with when()
- Integration with Medusa modules
- Error handling
Use when: Implementing complex business logic with multiple steps and rollback requirements
// Example: Order processing, Entity synchronization, Report generation
4. subscriber-complete.ts
Complete Event Subscriber
Includes:
- Basic event handling
- Workflow execution in subscribers
- Service resolution patterns
- Multi-event subscribers
- Conditional logic
- Retry mechanisms
- Error handling
Use when: Responding to Medusa events (order.placed, product.created, etc.)
// Example: Send emails, Sync to external systems, Update related data
5. module-link.ts
Module Link Patterns
Includes:
- Basic link between modules
- List links (one-to-many)
- Delete cascade configuration
- Custom columns in link tables
- Creating and dismissing links
- Querying linked data
Use when: Creating relationships between data models in different modules
// Example: Product <-> Brand, Restaurant <-> Products, Order <-> DigitalProduct
6. scheduled-job.ts
Scheduled Job Patterns
Includes:
- Basic scheduled jobs
- Service resolution
- Batch processing
- Workflow execution
- External API integration
- Cleanup tasks
- Common cron patterns
- Error handling
Use when: Running recurring automated tasks
// Example: Sync inventory, Generate reports, Cleanup old data
Quick Start
Using a Template
- Choose the appropriate template for your use case
- Copy the template to your project location
- Rename files and identifiers to match your domain
- Customize the logic for your specific requirements
- Test thoroughly before deploying
Example: Creating a Custom Module
# 1. Copy the template
cp templates/module-complete.ts src/modules/brand/
# 2. Rename and structure
src/modules/brand/
├── models/
│ ├── brand.ts
│ └── brand-ambassador.ts
├── services/
│ └── analytics.ts
├── service.ts
└── index.ts
# 3. Generate migrations
npx medusa db:generate brand
# 4. Run migrations
npx medusa db:migrate
# 5. Register in medusa-config.ts
modules: [
{
resolve: "./src/modules/brand"
}
]
Template Combinations
Templates are designed to work together. Common combinations:
E-commerce Extension
- module-complete.ts → Create Brand Module
- module-link.ts → Link Brand to Product
- api-route-complete.ts → Create Brand API endpoints
- workflow-complete.ts → Process brand synchronization
- subscriber-complete.ts → Handle brand.created event
Data Synchronization
- workflow-complete.ts → Sync workflow with steps
- scheduled-job.ts → Run sync periodically
- subscriber-complete.ts → Sync on specific events
- module-link.ts → Link synced entities
Custom Commerce Flow
- module-complete.ts → Create custom entities
- workflow-complete.ts → Implement business logic
- api-route-complete.ts → Expose APIs
- module-link.ts → Link to Cart/Order modules
- subscriber-complete.ts → Handle order completion
Best Practices
Code Organization
src/
├── modules/ # Custom modules
│ └── [module-name]/
│ ├── models/ # Data models
│ ├── services/ # Additional services
│ ├── service.ts # Main service
│ └── index.ts # Module definition
├── workflows/ # Business logic workflows
│ └── [workflow-name]/
│ ├── steps/ # Individual steps
│ └── index.ts # Workflow composition
├── api/ # API routes
│ └── [route-name]/
│ ├── route.ts # Route handlers
│ ├── [id]/
│ │ └── route.ts
│ └── validators.ts
├── subscribers/ # Event handlers
├── jobs/ # Scheduled tasks
└── links/ # Module links
Naming Conventions
Modules
// Module name (snake_case)
export const BRAND_MODULE = "brandModuleService"
// Data model (snake_case table name)
const Brand = model.define("brand", { ... })
// Service class (PascalCase)
class BrandModuleService extends MedusaService({ ... })
API Routes
// Route path: /api/brands
// Location: src/api/brands/route.ts
// Single item: /api/brands/:id
// Location: src/api/brands/[id]/route.ts
Workflows
// Workflow name (kebab-case)
export const syncBrandWorkflow = createWorkflow(
"sync-brand",
function (input) { ... }
)
// Step name (kebab-case)
export const validateBrandStep = createStep(
"validate-brand",
async (input) => { ... }
)
Subscribers
// File name: kebab-case, describes event
// src/subscribers/brand-created.ts
// Event name: dot notation
export const config: SubscriberConfig = {
event: "brand.created"
}
Type Safety
Always use TypeScript types:
// Input/Output types
export type WorkflowInput = {
entityId: string
data: Record<string, any>
}
export type WorkflowOutput = {
success: boolean
entity: any
}
// Zod schemas for validation
export const CreateEntitySchema = z.object({
name: z.string().min(1),
price: z.number().positive()
})
export type CreateEntityType = z.infer<typeof CreateEntitySchema>
Error Handling
Always implement proper error handling:
try {
// Operation
logger.info("Operation started", { context })
const result = await operation()
logger.info("Operation completed", { result })
return result
} catch (error) {
logger.error("Operation failed", {
error: error.message,
context
})
// Re-throw or handle gracefully
throw error
}
Troubleshooting
Module Not Found
# Ensure module is registered in medusa-config.ts
modules: [
{
resolve: "./src/modules/[module-name]"
}
]
# Restart server
npm run dev
Link Not Synced
# Sync links after creating link definition
npx medusa db:sync-links
# Or run full migration
npx medusa db:migrate
Validation Errors
// Ensure middleware is applied
// src/api/middlewares.ts
export default defineMiddlewares({
routes: [
{
matcher: "/your-route",
method: ["POST"],
middlewares: [
validateAndTransformBody(YourSchema)
]
}
]
})
Service Resolution Fails
// Check module name matches registration
export const MODULE_NAME = "moduleService"
// Resolve with correct name
const service = container.resolve(MODULE_NAME)
Testing Templates
Each template can be tested individually:
# Test module
./scripts/create-module.sh test-module
# Test API route
./scripts/create-api-route.sh test-route
curl http://localhost:9000/api/test-route
# Test workflow (create test API route)
POST /api/test-workflow
{ "input": { ... } }
# Test subscriber (emit test event)
await eventBus.emit({ name: "test.event", data: { ... } })
# Test scheduled job (create test trigger)
GET /api/trigger-job
Additional Resources
- MedusaJS Documentation
- Medusa CLI Reference
- Data Model Reference
- Workflow SDK Reference
- Medusa Examples
Contributing
These templates are based on official Medusa documentation and real-world patterns. Feel free to:
- Extend templates with additional patterns
- Submit improvements and corrections
- Share your custom variations
- Report issues or missing patterns
License
MIT - Use freely in your MedusaJS projects.