Help us improve
Share bugs, ideas, or general feedback.
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-commerceHow this skill is triggered — by the user, by Claude, or both
Slash command
/medusa-commerce:node-backendThis 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.
Sets up Medusa v2 development environment: CLI scaffolding with create-medusa-app, PostgreSQL/Redis prerequisites, medusa-config.ts configuration, directory structure, environment variables. Use when starting a new Medusa project.
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:
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.