From medusa-commerce
Builds Node.js backends for Medusa v2 using Express middleware chains, MikroORM entity patterns, PostgreSQL pooling, async patterns, error handling, and logging.
npx claudepluginhub orcaqubits/agentic-commerce-skills-plugins --plugin medusa-commerceThis skill is limited to using the following tools:
**Fetch live docs**:
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Fetch live docs:
site:docs.medusajs.com api routes middlewares express for middleware configurationsite:mikro-orm.io docs for MikroORM entity and query patternssite:docs.medusajs.com error handling MedusaError for error typeshttps://docs.medusajs.com/learn/fundamentals/api-routes for API route conventionssite:node.org docs async_hooks performance for Node.js async best practicesMedusa v2 is built on Express. Every HTTP request flows through a defined middleware chain:
Incoming Request
├── 1. CORS middleware
├── 2. Body parser (JSON)
├── 3. Cookie parser / session
├── 4. Authentication middleware
├── 5. Custom middlewares (middlewares.ts)
├── 6. Route handler (route.ts)
└── 7. Error handler
Define custom middleware in src/api/middlewares.ts:
// Fetch live docs for defineMiddlewares
// and MiddlewareRoute type signatures
import { defineMiddlewares } from "@medusajs/medusa"
| Middleware Property | Purpose |
|---|---|
matcher | Route pattern to match (glob or regex) |
method | HTTP method filter (GET, POST, etc.) |
middlewares | Array of Express middleware functions |
bodyParser | Configure or disable body parsing |
authenticate | Apply auth requirements |
Middleware executes in the order defined in the routes array. Global middleware (matcher *) runs before route-specific middleware.
Medusa v2 abstracts MikroORM behind DML. However, understanding the underlying ORM helps with advanced queries:
| DML Layer | MikroORM Layer | Purpose |
|---|---|---|
model.define() | @Entity() decorator | Define database entity |
| DML fields | @Property() decorators | Column definitions |
| DML relationships | @OneToMany(), @ManyToOne() | Relationship mappings |
DML .index() | @Index() decorator | Database indexes |
| Generated migrations | MikroORM migration files | Schema changes |
Module services generated by MedusaService provide typed query methods:
| Operation | Service Method | Underlying ORM Action |
|---|---|---|
| Find many | list(filters, config) | em.find() with criteria |
| Find one | retrieve(id, config) | em.findOneOrFail() |
| Create | create(data) | em.create() + em.persist() |
| Update | update(data) | em.assign() + em.flush() |
| Delete | delete(id) | em.removeAndFlush() |
| Soft delete | softDelete(id) | Set deleted_at timestamp |
MikroORM uses the Unit of Work pattern — changes are tracked and flushed together per request.
Medusa uses MikroORM's built-in PostgreSQL driver with connection pooling:
| Setting | Default | Production Recommendation |
|---|---|---|
| Pool minimum | 2 | 5-10 |
| Pool maximum | 10 | 20-50 (based on load) |
| Idle timeout | 30s | 10-30s |
| Connection timeout | 5s | 5-10s |
| SSL mode | Disabled | require or verify-full |
DATABASE_URL query parameters or medusa-config.ts database optionspg_stat_activitymax_connections (reserve for admin)| Pattern | Use Case | Avoid |
|---|---|---|
async/await | Sequential async operations | Callback-based patterns |
Promise.all() | Parallel independent operations | Sequential awaits for independent tasks |
Promise.allSettled() | Parallel ops where some may fail | Promise.all() when partial success is OK |
for await...of | Async iterators, streams | Manual iterator consumption |
try/catch in async | Error handling in async functions | Unhandled promise rejections |
Workflow steps are inherently async. Each step receives context and returns a StepResponse:
// Fetch live docs for createStep async
// signature and StepResponse typing
Subscribers handle events asynchronously. They execute in the worker process when running in separate mode:
| Concept | Implementation |
|---|---|
| Event emission | Automatic on entity changes or manual via event bus |
| Subscriber registration | Export config with event and handler function |
| Execution context | Runs in worker process (async from request) |
| Error handling | Subscriber errors do not affect the triggering request |
| Error Class | HTTP Status | Use Case |
|---|---|---|
MedusaError | Varies | Base error class with type codes |
NOT_FOUND | 404 | Entity not found |
INVALID_DATA | 400 | Validation failure |
UNAUTHORIZED | 401 | Authentication required |
NOT_ALLOWED | 403 | Insufficient permissions |
CONFLICT | 409 | Duplicate or conflicting state |
UNEXPECTED_STATE | 500 | Internal logic error |
// Fetch live docs for MedusaError import
// and error type enum values
import { MedusaError } from "@medusajs/framework/utils"
MedusaError with appropriate type in service methodstry/catch in workflow steps and return compensation data on failureMedusa provides a structured logger accessible via the DI container:
| Log Level | Method | Use Case |
|---|---|---|
error | logger.error() | Unrecoverable errors, exceptions |
warn | logger.warn() | Degraded state, deprecated usage |
info | logger.info() | Significant events, startup, shutdown |
debug | logger.debug() | Detailed diagnostic information |
Resolve the logger from the container via container.resolve("logger"). Log at appropriate levels, include contextual data (entity IDs, operation names), and configure structured JSON output in production.
| Concern | Recommendation |
|---|---|
| Node.js version | Use Node.js 20+ (LTS) for Medusa v2 |
| Memory | Set --max-old-space-size for large catalogs |
| Event loop | Avoid blocking the event loop with synchronous operations |
| Graceful shutdown | Handle SIGTERM to close connections and finish in-flight requests |
| Clustering | Use multiple server instances (not Node cluster) behind a load balancer |
src/api/middlewares.ts; order middleware from general to specific; use route matchers to scope middleware narrowlylist with filters instead of raw queries; leverage soft deletes for data preservationawait async operations; use Promise.all for parallel independent work; handle errors in every try/catch block with meaningful error typesconfig.relations to eager-load relationshipsFetch the Medusa API route and middleware documentation for exact handler signatures, error types, and logging configuration before implementing.