> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/medusajs/medusa/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture

> Learn about Medusa's modular architecture, workflow engine, framework structure, and design patterns.

# Architecture

Medusa is built on a modular, composable architecture that separates concerns into distinct layers: modules, workflows, API routes, and the framework runtime.

## Architecture Overview

```
┌─────────────────────────────────────────────────────────┐
│                     API Layer                           │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐ │
│  │ Admin Routes │  │ Store Routes │  │Custom Routes │ │
│  └──────────────┘  └──────────────┘  └──────────────┘ │
└────────────────────────┬────────────────────────────────┘
                         │
┌────────────────────────▼────────────────────────────────┐
│                  Workflow Layer                         │
│  ┌──────────────────────────────────────────────────┐  │
│  │  Workflows (Business Logic Orchestration)        │  │
│  │  - createProductWorkflow                         │  │
│  │  - processOrderWorkflow                          │  │
│  │  - Custom workflows                              │  │
│  └──────────────────────────────────────────────────┘  │
└────────────────────────┬────────────────────────────────┘
                         │
┌────────────────────────▼────────────────────────────────┐
│                   Module Layer                          │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐  │
│  │ Product  │ │   Cart   │ │  Order   │ │ Payment  │  │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘  │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐  │
│  │Customer  │ │Inventory │ │Promotion │ │   ...    │  │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘  │
└────────────────────────┬────────────────────────────────┘
                         │
┌────────────────────────▼────────────────────────────────┐
│                Framework Layer                          │
│  - Dependency Injection (Awilix)                        │
│  - Database (PostgreSQL via MikroORM)                   │
│  - HTTP Server (Express)                                │
│  - Event Bus                                            │
│  - Caching                                              │
│  - Job Queue                                            │
└─────────────────────────────────────────────────────────┘
```

## Core Concepts

### Modules

Modules are self-contained packages that handle specific business domains. Each module:

* Manages its own data models and database schema
* Exposes a service interface for business logic
* Can be used independently or composed together
* Is versioned and published to npm

**Module structure**:

```typescript theme={null}
@medusajs/product/
├── src/
│   ├── models/         # Database entities
│   ├── services/       # Business logic
│   ├── repositories/   # Data access
│   ├── migrations/     # Database migrations
│   └── index.ts        # Module exports
```

**Available modules**:

<CardGroup cols={3}>
  <Card title="Product" icon="box">
    Catalog, variants, options, collections
  </Card>

  <Card title="Cart" icon="shopping-cart">
    Shopping cart, line items, totals
  </Card>

  <Card title="Order" icon="receipt">
    Order management, fulfillment, returns
  </Card>

  <Card title="Payment" icon="credit-card">
    Payment processing, refunds
  </Card>

  <Card title="Customer" icon="user">
    Customer accounts, groups
  </Card>

  <Card title="Inventory" icon="warehouse">
    Stock levels, reservations
  </Card>

  <Card title="Fulfillment" icon="truck">
    Shipping, delivery providers
  </Card>

  <Card title="Promotion" icon="tag">
    Discounts, campaigns, rules
  </Card>

  <Card title="Notification" icon="bell">
    Multi-channel notifications
  </Card>
</CardGroup>

### Workflows

Workflows orchestrate complex business processes by composing steps. They provide:

* **Compensation logic**: Automatic rollback on failures
* **Type safety**: Full TypeScript support
* **Composability**: Reuse steps across workflows
* **Observability**: Built-in hooks and events

**Workflow anatomy**:

```typescript theme={null}
import {
  createWorkflow,
  createStep,
  StepResponse,
  WorkflowData,
  WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"

// Define a step with compensation
const reserveInventoryStep = createStep(
  "reserve-inventory",
  async (productId: string, { container }) => {
    const inventoryService = container.resolve("inventoryService")
    const reservation = await inventoryService.reserve(productId, 1)
    
    // Return data and compensation data
    return new StepResponse(reservation, reservation.id)
  },
  // Compensation function (rollback)
  async (reservationId, { container }) => {
    if (!reservationId) return
    const inventoryService = container.resolve("inventoryService")
    await inventoryService.cancelReservation(reservationId)
  }
)

// Compose workflow from steps
const createOrderWorkflow = createWorkflow(
  "create-order",
  (input: WorkflowData<{ productId: string; customerId: string }>) => {
    // Steps execute in sequence
    const reservation = reserveInventoryStep(input.productId)
    const order = createOrderStep({
      customerId: input.customerId,
      productId: input.productId,
    })
    const payment = processPaymentStep(order.id)
    
    return new WorkflowResponse(order)
  }
)
```

**Workflow execution**:

```typescript theme={null}
import { createOrderWorkflow } from "./workflows/create-order"

const { result, errors } = await createOrderWorkflow(container)
  .run({
    input: {
      productId: "prod_123",
      customerId: "cust_456",
    },
  })

if (errors) {
  // All steps are automatically compensated
  console.error("Order creation failed:", errors)
} else {
  console.log("Order created:", result)
}
```

### API Routes

API routes define HTTP endpoints with full framework integration:

```typescript theme={null}
// src/api/store/products/route.ts
import {
  MedusaRequest,
  MedusaResponse,
} from "@medusajs/framework/http"
import { HttpTypes } from "@medusajs/framework/types"

export const GET = async (
  req: MedusaRequest<HttpTypes.StoreProductListParams>,
  res: MedusaResponse<HttpTypes.StoreProductListResponse>
) => {
  // Access query via dependency injection
  const query = req.scope.resolve("query")
  
  const { data: products, metadata } = await query.graph({
    entity: "product",
    fields: req.queryConfig.fields,
    filters: req.filterableFields,
    pagination: req.queryConfig.pagination,
  })
  
  res.json({
    products,
    count: metadata.count,
    offset: metadata.skip,
    limit: metadata.take,
  })
}

export const POST = async (
  req: MedusaRequest<HttpTypes.AdminCreateProduct>,
  res: MedusaResponse<HttpTypes.AdminProductResponse>
) => {
  const { result } = await createProductsWorkflow(req.scope)
    .run({
      input: { products: [req.body] },
    })
  
  res.json({ product: result[0] })
}
```

**Route file location determines URL**:

```
src/api/
├── admin/
│   └── products/
│       ├── route.ts           → /admin/products
│       └── [id]/
│           └── route.ts       → /admin/products/:id
└── store/
    └── products/
        └── route.ts           → /store/products
```

### Framework Runtime

The `@medusajs/framework` package provides the core runtime that powers Medusa:

**Key components**:

<Steps>
  <Step title="Dependency Injection Container">
    Uses [Awilix](https://github.com/jeffijoe/awilix) for dependency management:

    ```typescript theme={null}
    // Access any service or module
    const productService = container.resolve("productModuleService")
    const query = container.resolve("query")
    ```

    From `@medusajs/framework/src/container.ts`
  </Step>

  <Step title="Database Layer">
    PostgreSQL integration via [MikroORM](https://mikro-orm.io/):

    * Automatic migrations
    * Entity relationships
    * Query builder
    * Transaction management

    From `@medusajs/framework/src/database/`
  </Step>

  <Step title="HTTP Server">
    Express-based server with middleware:

    * CORS configuration
    * Authentication
    * Request validation
    * Response serialization

    From `@medusajs/framework/src/http/`
  </Step>

  <Step title="Event Bus">
    Pub/sub system for async communication:

    ```typescript theme={null}
    import { Modules } from "@medusajs/framework/utils"

    const eventBus = container.resolve(Modules.EVENT_BUS)
    await eventBus.emit("order.placed", { orderId: "123" })
    ```
  </Step>

  <Step title="Workflow Engine">
    Orchestration runtime from `@medusajs/orchestration`:

    * Step execution
    * Compensation handling
    * State management
    * Retry logic
  </Step>
</Steps>

## Module Architecture

Each module follows a consistent internal structure:

### Service Layer

Services contain business logic and use decorators for cross-cutting concerns:

```typescript theme={null}
// packages/modules/product/src/services/product-module-service.ts
import {
  InjectManager,
  InjectTransactionManager,
  MedusaContext,
  MedusaService,
} from "@medusajs/framework/utils"

export class ProductModuleService 
  extends MedusaService<{ Product: { dto: ProductDTO } }>
  implements IProductModuleService
{
  // Public method with manager injection
  @InjectManager()
  async createProducts(
    data: CreateProductDTO[],
    @MedusaContext() sharedContext: Context = {}
  ) {
    return await this.createProducts_(data, sharedContext)
  }
  
  // Protected implementation with transaction manager
  @InjectTransactionManager()
  protected async createProducts_(
    data: CreateProductDTO[],
    @MedusaContext() sharedContext: Context = {}
  ) {
    const products = data.map((d) => this.productService_.create(d))
    return await this.productService_.save(products, sharedContext)
  }
}
```

**Decorator patterns from CLAUDE.md**:

* `@InjectManager()` - Inject entity manager (public methods)
* `@InjectTransactionManager()` - Inject transaction manager (protected methods)
* `@MedusaContext()` - Inject shared context parameter
* `@EmitEvents()` - Emit domain events after operation

### Model Layer

Data models use MikroORM entities:

```typescript theme={null}
import { model } from "@medusajs/framework/utils"

const Product = model.define("product", {
  id: model.id().primaryKey(),
  title: model.text(),
  description: model.text().nullable(),
  handle: model.text(),
  status: model.enum(["draft", "published", "rejected"]),
  variants: model.hasMany(() => ProductVariant),
  categories: model.manyToMany(() => ProductCategory),
  created_at: model.dateTime(),
  updated_at: model.dateTime(),
})
```

### Repository Layer

Repositories handle data access:

```typescript theme={null}
export class ProductRepository extends DAL.Repository {
  async findByHandle(handle: string) {
    return await this.find({ handle })
  }
  
  async findWithVariants(id: string) {
    return await this.findOne(
      { id },
      { populate: ["variants"] }
    )
  }
}
```

## Configuration

Medusa's configuration is defined in `medusa-config.ts`:

```typescript medusa-config.ts theme={null}
import { defineConfig, Modules } from "@medusajs/framework/utils"

export default defineConfig({
  // Project configuration
  projectConfig: {
    databaseUrl: process.env.DATABASE_URL,
    http: {
      storeCors: process.env.STORE_CORS,
      adminCors: process.env.ADMIN_CORS,
      jwtSecret: process.env.JWT_SECRET,
      cookieSecret: process.env.COOKIE_SECRET,
    },
    redisUrl: process.env.REDIS_URL,
    workerMode: "shared", // or "worker" or "server"
  },
  
  // Admin configuration
  admin: {
    path: "/app",
    backendUrl: process.env.MEDUSA_BACKEND_URL,
  },
  
  // Module configuration
  modules: {
    [Modules.PRODUCT]: {
      resolve: "@medusajs/product",
    },
    [Modules.PAYMENT]: {
      resolve: "@medusajs/payment",
      options: {
        providers: [
          {
            resolve: "@medusajs/payment-stripe",
            id: "stripe",
            options: {
              apiKey: process.env.STRIPE_API_KEY,
            },
          },
        ],
      },
    },
    [Modules.FILE]: {
      resolve: "@medusajs/file",
      options: {
        providers: [
          {
            resolve: "@medusajs/file-s3",
            id: "s3",
            options: {
              bucket: process.env.S3_BUCKET,
              region: process.env.S3_REGION,
            },
          },
        ],
      },
    },
  },
  
  // Feature flags
  featureFlags: {
    index_engine: true,
  },
})
```

Configuration handling from `packages/core/framework/src/config/config.ts`

## Monorepo Structure

Medusa's source code is organized as a Yarn 3 monorepo:

```
medusa/
├── packages/
│   ├── core/
│   │   ├── framework/          # @medusajs/framework
│   │   ├── workflows-sdk/      # @medusajs/workflows-sdk
│   │   ├── core-flows/         # @medusajs/core-flows
│   │   ├── types/              # @medusajs/types
│   │   ├── utils/              # @medusajs/utils
│   │   └── modules-sdk/        # @medusajs/modules-sdk
│   ├── modules/
│   │   ├── product/            # @medusajs/product
│   │   ├── cart/               # @medusajs/cart
│   │   ├── order/              # @medusajs/order
│   │   ├── payment/            # @medusajs/payment
│   │   └── .../                # 30+ modules
│   ├── medusa/                 # @medusajs/medusa (main package)
│   ├── admin/
│   │   └── dashboard/          # @medusajs/admin-dashboard
│   └── cli/
│       ├── medusa-cli/         # @medusajs/cli
│       └── create-medusa-app/  # create-medusa-app
├── integration-tests/          # Full-stack tests
└── package.json                # Workspace config
```

From `~/workspace/source/README.md` and `package.json`

## Request Lifecycle

Understanding how a request flows through Medusa:

<Steps>
  <Step title="HTTP Request">
    Client sends request to `/admin/products`
  </Step>

  <Step title="Routing">
    Express routes to `src/api/admin/products/route.ts`
  </Step>

  <Step title="Middleware">
    * Authentication (JWT verification)
    * CORS headers
    * Request validation
    * Query parsing
  </Step>

  <Step title="Handler Execution">
    Route handler executes:

    ```typescript theme={null}
    export const GET = async (req, res) => {
      // Handler has access to:
      // - req.scope (DI container)
      // - req.filterableFields (parsed filters)
      // - req.queryConfig (fields, pagination)
    }
    ```
  </Step>

  <Step title="Workflow Invocation">
    Handler invokes workflow:

    ```typescript theme={null}
    const { result } = await createProductsWorkflow(req.scope)
      .run({ input: req.body })
    ```
  </Step>

  <Step title="Step Execution">
    Workflow executes steps sequentially:

    * Validates input
    * Calls module services
    * Handles errors with compensation
  </Step>

  <Step title="Module Service">
    Module service performs business logic:

    * Data validation
    * Database operations
    * Event emission
  </Step>

  <Step title="Response">
    Handler returns JSON response:

    ```typescript theme={null}
    res.json({ product: result })
    ```
  </Step>
</Steps>

## Error Handling

Medusa uses `MedusaError` for consistent error handling:

```typescript theme={null}
import { MedusaError } from "@medusajs/framework/utils"

// Throw typed errors
if (!product) {
  throw new MedusaError(
    MedusaError.Types.NOT_FOUND,
    `Product with id: ${id} was not found`
  )
}

if (order.status === "cancelled") {
  throw new MedusaError(
    MedusaError.Types.NOT_ALLOWED,
    "Cannot update a cancelled order"
  )
}
```

**Error types**:

* `NOT_FOUND` - Resource doesn't exist
* `INVALID_DATA` - Invalid input or state
* `NOT_ALLOWED` - Operation not permitted
* `DUPLICATE_ERROR` - Unique constraint violation
* `UNAUTHORIZED` - Authentication required
* `PAYMENT_AUTHORIZATION_ERROR` - Payment processing failed

From CLAUDE.md section 5.4

## Event System

Modules emit events for async operations:

```typescript theme={null}
// Subscribe to events
import { Modules } from "@medusajs/framework/utils"

export default async function productCreatedHandler({
  event,
  container,
}) {
  const { id } = event.data
  const productService = container.resolve(Modules.PRODUCT)
  
  // Perform async operation
  const product = await productService.retrieve(id)
  await sendNotification(product)
}

export const config = {
  event: "product.created",
}
```

**Common events**:

* `product.created`, `product.updated`, `product.deleted`
* `order.placed`, `order.fulfilled`, `order.canceled`
* `cart.created`, `cart.updated`
* `customer.created`, `customer.updated`

## Development Workflow

### Local Development

```bash theme={null}
# Watch mode with hot reload
npm run dev

# Build TypeScript
npm run build

# Run tests
npm test

# Database migrations
npm run migrations:run
```

### Testing Strategy

* **Unit tests**: `packages/*/__tests__/*.spec.ts`
* **Integration tests**: `packages/*/integration-tests/__tests__/*.spec.ts`
* **API tests**: `integration-tests/http/__tests__/*.spec.ts`
* **Framework**: Jest 29 (backend), Vitest 3 (frontend)

From CLAUDE.md section 3

## Performance Considerations

<Tip>
  **Database Indexing**: Modules automatically create indexes on foreign keys and frequently queried fields.
</Tip>

<Tip>
  **Query Optimization**: Use the Query API for efficient data fetching with automatic join optimization.
</Tip>

<Tip>
  **Caching**: Enable Redis for session storage and caching:

  ```typescript theme={null}
  projectConfig: {
    redisUrl: process.env.REDIS_URL,
  }
  ```
</Tip>

<Tip>
  **Worker Mode**: Separate HTTP and background workers:

  ```bash theme={null}
  # Server mode (HTTP only)
  MEDUSA_WORKER_MODE=server npm start

  # Worker mode (background jobs only)
  MEDUSA_WORKER_MODE=worker npm start
  ```
</Tip>

## Next Steps

<CardGroup cols={2}>
  <Card title="Create Your First Workflow" icon="diagram-project">
    Learn to build custom workflows with compensation logic
  </Card>

  <Card title="Build Custom Modules" icon="cube">
    Extend Medusa with your own business domain modules
  </Card>

  <Card title="API Route Development" icon="code">
    Create custom API endpoints with full type safety
  </Card>

  <Card title="Module Development" icon="puzzle-piece">
    Deep dive into module architecture and patterns
  </Card>
</CardGroup>
