---
title: From 1.x to 2.0
description: What changed and how to port your existing Mercur 1.x code to 2.0.
---

# Migrating from 1.x to 2.0

Start with a working 2.0 project (see [Installation](/getting-started/installation)). This guide covers what to change when porting your 1.x code.

<Note>
**Using version older than 1.4.0?** Your admin panel code is inside the backend repo (not a separate app). When scanning for custom admin code to port, look there instead of `apps/admin/`. Everything else in this guide applies identically.
</Note>

## Package Mapping

| 1.x Package | 2.0 Equivalent |
|-------------|----------------|
| `@mercurjs/b2c-core` | `@mercurjs/core` |
| `@mercurjs/commission` | Built into core |
| `@mercurjs/algolia` | Block: `mercurjs add algolia` |
| `@mercurjs/resend` | No 2.0 equivalent — port manually |
| `@mercurjs/payment-stripe-connect` | No 2.0 equivalent — port manually |
| `@mercurjs/stripe-tax-provider` | No 2.0 equivalent — port manually |
| `@medusajs/admin-vite-plugin` | `@mercurjs/dashboard-sdk` |
| `@medusajs/js-sdk` | `@mercurjs/client` |

## Directory Mapping

| 1.x | 2.0 |
|-----|-----|
| `apps/backend/src/*` | `packages/api/src/*` |
| `apps/admin/src/routes/` | `apps/admin/src/pages/` |
| `apps/vendor/src/routes/` | `apps/vendor/src/pages/` |

## What You DON'T Need to Port

Built into core today:

- `seller`
- `payout`
- `commission`

Moved to registry blocks:

- `reviews`
- `requests`
- `wishlist`
- `team-management`
- `algolia`
- `vendor-notifications`
- `vendor-chat`
- `product-import-export`

Install these blocks instead of porting their 1.x package code.

## Current Migration Exceptions

These areas do not currently have full 1.x parity and should be treated as manual migration work:

- **`TaxCode`** — no 2.0 equivalent today. Port the old logic manually if your project depends on it.
- **`SecondaryCategory`** — no full 1.x parity today. Port manually for now if your project depends on it. Fuller support is planned for a future 2.x release.
- **Product attributes** — the 1.x attribute module is not carried over 1:1. Port manually for now if your project depends on it. Fuller support is planned for a future 2.x release.

## Order Set to Order Group

The 1.x `OrderSet` entity has been renamed to **`OrderGroup`** in 2.0. This is a breaking change that affects database tables, API endpoints, workflow names, event names, and types.

### What changed

| Aspect | 1.x | 2.0 |
|--------|-----|-----|
| Entity / table | `order_set` | `order_group` |
| ID prefix | `os_` | `og_` |
| API endpoints | `/admin/order-sets`, `/store/order-set` | `/admin/order-groups`, `/store/order-groups` |
| Workflows | `getFormattedOrderSetListWorkflow` | `getOrderGroupsListWorkflow`, `getOrderGroupDetailWorkflow` |
| Events | `OrderSetWorkflowEvents` | `OrderGroupWorkflowEvents` |
| Types | `OrderSetDTO` | `OrderGroupDTO` (from `@mercurjs/types`) |

### Removed fields

Two fields that existed on `OrderSet` in 1.x have been **removed** from `OrderGroup`:

- **`payment_collection_id`** — Payment collections are now linked at the individual **order** level, not at the group level. Each per-seller order gets its own link to the cart's payment collection during checkout. To get the payment collection, query the linked orders instead of the group.
- **`sales_channel_id`** — Sales channel information is stored on each individual order, not on the group.

### New computed fields

Two fields are now **computed at query time** (not stored as columns):

- **`seller_count`** — Count of distinct sellers across all linked orders
- **`total`** — Sum of order totals from linked order summaries

### Migration steps

1. Update imports: `OrderSetDTO` → `OrderGroupDTO` (from `@mercurjs/types`)
2. Update API calls: `/order-sets` → `/order-groups`
3. Update workflow references: `getFormattedOrderSetListWorkflow` → `getOrderGroupsListWorkflow`
4. Update event listeners: `OrderSetWorkflowEvents` → `OrderGroupWorkflowEvents`
5. If you used `payment_collection_id` or `sales_channel_id` from the order set, retrieve these from the individual orders instead (via the `order_group_order` link)

See [Order Groups](/core-concepts/order-groups) for the full 2.0 data model and API reference.

## Porting Custom Backend Code

### Modules

Copy to `packages/api/src/modules/`, register in `medusa-config.ts`. Update imports from `@mercurjs/b2c-core` to `@mercurjs/core`.

### Workflows

Copy to `packages/api/src/workflows/<entity>/`. Don't create barrel `index.ts` files — conflicts with block installation.

### API Routes

Copy to `packages/api/src/api/`. Type both generics — codegen reads these:

```typescript
export const GET = async (
  req: AuthenticatedMedusaRequest<BodyType>,
  res: MedusaResponse<ResponseType>
) => { ... }
```

Run `bunx @mercurjs/cli@latest codegen` after adding routes.

### Links and Subscribers

Copy to `packages/api/src/links/` and `src/subscribers/`. Don't duplicate links that core already provides (seller↔product, seller↔order, etc.).

### Custom Providers

Copy to `packages/api/src/providers/`. Two required changes:

```typescript
// medusa-config.ts — must use ./src/ prefix
resolve: './src/providers/my-provider'

// provider index.ts — must import from framework/utils
import { Modules, ModuleProvider } from "@medusajs/framework/utils"
```

## Porting Custom Dashboard Code

Only if you have custom pages not covered by core-admin/vendor.

| Old import | New import |
|-----------|------------|
| `@medusajs/js-sdk` | `@mercurjs/client` |
| `@custom-types/*` | `@mercurjs/types` |
| `@hooks/*`, `@components/*`, `@lib/*` | Keep local, or `@mercurjs/dashboard-shared` if the symbol exists there |

Move pages from `src/routes/` to `src/pages/` with `export default`.