v2.8.0
medusajs/medusav2.8.0May 13, 2025by olivermrbl
AI Summary
This release improves cart-completion robustness, introduces an experimental Index module for cross-module filtering, and introduces full support for custom Tax Providers.
Key Highlights
- Improve cart-completion robustness by changing idempotency and restructuring the workflow.
- Introduce experimental cross-module filtering via a new Index module.
- Introduce full support for custom Tax Providers.
- Change line item title source from variant to product.
Breaking Changes
- Cart-completion workflow: `idempotent` flag changed from `true` to `false`.
- Cart-completion workflow: Payment authorization moved to the end of the workflow.
- Line item generation: Title source changed from variant to product.
New Features
- Custom Tax Providers support.
- Experimental Index module for cross-module filtering.
- Restructured cart-completion workflow.
Full Release Notes
<!--

# v2.8.0: More robust cart-completion, cross-module filtering, and Tax Providers
This release improves the robustness of the cart-completion workflow, enables cross-module filtering via a new module, and introduces full support for custom Tax Providers.
CMS_BREAK -->
## Highlights
### Important: This release introduced a regression with product updates
We unintentionally introduced a regression that affected the ordering of products returned from the product module service. This broke workflows (e.g. updateProductsWorkflow) that rely on consistent ordering for subsequent operations such as applying price updates.
Upgrade to v2.8.1 as soon as possible to avoid any issues related to this change.
### Cart-completion robustness
> [!WARNING]
Breaking changes
This release introduces important changes to the `completeCartWorkflow` aimed at improving robustness and making it easier to recover from failures.
**Changes to idempotency**
Until now, the workflow has had the following configuration:
```ts
{
name: completeCartWorkflowId
store: true,
idempotent: true,
retentionTime: THREE_DAYS,
}
```
Here's a brief description of what these properties do, excluding `name`:
- `store`: Store the workflow execution. If no retention time is specified, the workflow is only stored for the duration of its execution
- `idempotent`: Store the result of the _first_ workflow execution and return it on subsequent runs
- `retentionTime`: Store the result in the configured data store for "x" amount of time–here, three days
In this release, we change the `idempotent` flag from true to false. Initially, the idea of having an idempotent cart-completion stemmed from wanting to ensure that multiple requests to complete the same cart would lead to the same outcome. This is, in of itself, still reasonable to ensure there is only ever one attempt to complete the same cart. However, in case of failures, the idempotent mechanism makes it challenging to recover, since a new cart with the same details is required to re-attempt the completion. This is because the result of the failing workflow is stored and returned on all subsequent runs, regardless of whether the cart is updated to satisfy the constraints for completion.
With `idempotent` set to false, it will be possible to retry failed executions, making it simpler to bring the cart to a satisfying state and eventually create the order.
It is worth mentioning that concurrency continues to be appropriately managed by passing the cart ID as the `transactionId` when running the workflow. The transaction ID ensures that only one workflow execution can run at a time.
**Changes to the structure**
The workflow has been slightly restructured to minimize the risk of payment sessions getting stuck in a state that is difficult to recover from. More specifically, the payment authorization step has been moved to the very end of the workflow, so that all first-party checks are performed before we authorize the payment.
To understand why this is important, we need to cover the `compensateIfNeeded` step of the workflow briefly. This step compensates active payment sessions in the case of failure to avoid orphaned third-party payments and recreates the Medusa payment session so that new payment details can be attached.
For example, suppose the payment authorization is performed off-band (e.g., in a webhook), and the cart-completion workflow fails to execute. In that case, the step will void the third-party payment and bring the cart to a correct state, all while ensuring consistency between the two systems.
Moving the payment authorization step to the end of the workflow ensures that we only create an authorized payment if all other cart constraints are satisfied.
**Changes to the webhook handler**
The webhook handler ensures consistency between Medusa and the third-party payment provider. More specifically, it will handle the following scenarios:
- Payment authorization: when we receive a payment authorization event, we will attempt to authorize and create a payment in Medusa
- Payment capture: when we receive a payment capture event, we will attempt to capture the associated payment in Medusa
- Cart-completion: when we receive a payment authorization event, we will attempt to complete the cart
- Payment authorization and capture: when we receive a payment capture event and there is no existing payment in Medusa, we will attempt to authorize, create, and capture a payment in Medusa
We have only handled the first three scenarios until now. This release introduces functionality for the fourth, a more unusual scenario involving auto-captures in the third-party payment provider.
### Line item generation
> [!WARNING]
Breaking changes
This release changes the source of line item titles and subtitles. The title has changed from the variant title to the product title, and the subtitle has changed from the product title to the variant title.
### Cross-module filters (experimental)
This release introduces experimental support for cross-module filters via a new module, `@medusajs/index`.
> Please remember that this module is experimental and in development, so please use it cautiously. It is subject to change as we finalize the design to enable cross-module filtering.
We will keep the description brief since the module is still in development. Here's what you need to know:
- Medusa's architecture is divided into a range of modules, each being isolated (at the data model level) from one another. By default, the modules share the same database, but the architecture is built to support external data sources, in case your module needs a different type of database, or you want to use a third-party service in place of Medusa's core module
- Consequently, queries to retrieve data are performed per module, and the data is aggregated in the end to create the result set
- Our new index module allows you to ingest data into a central, relational-like structure
- The structure enables efficient filtering over data coming from different data sources (provided it is ingested)
The index module can be enabled by installing the module:
```
yarn add @medusajs/index
```
Adding it to your Medusa config:
```
{
// ...rest of config
modules: [{ resolve: "@medusajs/index", options: {} }]
}
```
And finally, adding a feature flag to enable it:
```
// .env
MEDUSA_FF_INDEX_ENGINE=true
```
Then, apply the migrations to create the related tables:
```
npx medusa db:migrate
```
The next time you start your server, we will ingest data into the index engine.
In this first iteration, we only ingest the following core entities:
- Products
- Product Variants
- Prices
- Sales Channels
The data in the index is queried through a new API with semantics identical to the existing query graph:
```ts
const { data: products = [], metadata } = await query.index({
entity: "product",
fields: ["id", "name"],
});
```
In addition to ingesting a few select resources from the core, we have added support for ingesting data from custom modules through link definitions. For example, say you want to introduce a Brand on Products and filter your Products by it.
Assuming you have added a Brand module, you create a link as follows:
```ts
import { defineLink } from "@medusajs/framework/utils";
import ProductModule from "@medusajs/medusa/product";
import BrandModule from "../modules/brand";
export default defineLink(
{
linkable: ProductModule.linkable.product,
isList: true,
},
{
linkable: BrandModule.linkable.brand,
}
);
```
This link will associate the two data models and allow you to query them from both sides of the link.
Furthermore, to ingest the Brand into the index and make the data filterable, you need to add the new `filterable` property to the link:
```ts
import { defineLink } from "@medusajs/framework/utils";
import ProductModule from "@medusajs/medusa/product";
import BrandModule from "../modules/brand";
export default defineLink(
{
linkable: ProductModule.linkable.product,
isList: true,
},
{
linkable: BrandModule.linkable.brand,
filterable: ["id", "name"]
}
);
```
The link above specifies that Brands should be ingested into the index and made filterable via the properties `id` and `title`.
As a result, you can now filter Products by Brands ID or title like so:
```ts
const { data: products = [], metadata } = await query.index({
entity: "product",
fields: ["id", "title", "brand.*"],
filters: {
brand: {
name: "Hermes"
}
},
});
```
**An important trade-off in the index module** is the need to avoid the performance cost of `COUNT(*)` queries, which can be an incredibly high cost for very large data sets. Instead, we use Postgres’ internal query planner to compute an estimated count of the result set. For very small data sets, this estimate can be very inaccurate, but for larger ones it should provide a reasonable estimate. The trade-off allows us to achieve very fast response times making it ideal for user-facing search and browsing experiences. As noted earlier, the tool is still experimental, and we plan to continue iterating and improving it over time.
### Custom Tax Providers
This release introduces full support for custom Tax Providers by making these key changes:
- Load custom Tax Providers in the Tax Module
- Manage (create, update) provider per Tax Region in the admin dashboard
- Migrate all Tax Regions to use a tax provider
The migration script will run the first time you start the server after upgrading. It will assign the default system provider to the Tax Region, if the region did not have a custom provider specified already.
## Features
* feat: upgrade opentelemetry packages to support the latest release by @thetutlage in https://github.com/medusajs/medusa/pull/12266
* feat(index): add filterable fields to link definition by @carlos-r-l-rodrigues in https://github.com/medusajs/medusa/pull/11898
* feat: add needed methods to the file module and providers by @thetutlage in https://github.com/medusajs/medusa/pull/12325
* feat(core-flows, utils): add OrderEdit events by @fPolic in https://github.com/medusajs/medusa/pull/12320
* feat: implement direct upload by @thetutlage in https://github.com/medusajs/medusa/pull/12328
* feat(dashboard, js-sdk, medusa, tax, types): custom tax providers by @fPolic in https://github.com/medusajs/medusa/pull/12297
* feat(product): search variants by product properties by @fPolic in https://github.com/medusajs/medusa/pull/12391
* fix(workflow-engine-*): q text search by @adrien2p in https://github.com/medusajs/medusa/pull/12435
* feat(core-flows): Emit cart trasnferred customer by @adrien2p in https://github.com/medusajs/medusa/pull/12425
## Bugs
* fix(medusa): Fix store return API by @riqwan in https://github.com/medusajs/medusa/pull/12284
* fix(core-flows): handle inventory kit items in mark-as-shipped/delivered flows by @fPolic in https://github.com/medusajs/medusa/pull/12269
* fix(design-system): filter/sorting menu error by @fPolic in https://github.com/medusajs/medusa/pull/12309
* fix(core-flows): add missing remove remote link by @carlos-r-l-rodrigues in https://github.com/medusajs/medusa/pull/12326
* fix(core-flows,utils): move fulfillment workflow events by @shahednasser in https://github.com/medusajs/medusa/pull/12338
* fix: batch updates in upsertMany_ by @peterlgh7 in https://github.com/medusajs/medusa/pull/12333
* fix: export ProductImage to allow for custom links to add alt text by @thetutlage in https://github.com/medusajs/medusa/pull/12357
* fix(product): Return updated collections by @olivermrbl in https://github.com/medusajs/medusa/pull/12354
* fix(create-medusa-app): updates to text and prompts by @shahednasser in https://github.com/medusajs/medusa/pull/12360
* fix(medusa): Support additional data on admin/collections by @olivermrbl in https://github.com/medusajs/medusa/pull/12345
* fix(core-flows): export order-related utility workflows by @shahednasser in https://github.com/medusajs/medusa/pull/12380
* fix(medusa): check if tax module is installed when running tax migration script by @fPolic in https://github.com/medusajs/medusa/pull/12393
* fix: Use logger in the test runner and migration commands by @sradevski in https://github.com/medusajs/medusa/pull/12406
* fix: refactor batch product update by @peterlgh7 in https://github.com/medusajs/medusa/pull/12367
* fix(dashboard): tax regions UI polish by @fPolic in https://github.com/medusajs/medusa/pull/12437
* fix(core-flows): use product title for line item title by @fPolic in https://github.com/medusajs/medusa/pull/12397
* fix(dashboard): inventory kit combobox state by @fPolic in https://github.com/medusajs/medusa/pull/12371
* fix(core-flows): use transform as input to account holder step by @riqwan in https://github.com/medusajs/medusa/pull/12430
* fix(dashboard): call route modal onClose only on route change by @fPolic in https://github.com/medusajs/medusa/pull/12383
* fix(core-flows): Refund and recreate payment session on cart complete failure by @fPolic in https://github.com/medusajs/medusa/pull/12263
* fix(tax): Make system provider registration backward compatible by @olivermrbl in https://github.com/medusajs/medusa/pull/12441
* fix(dashboard, medusa): validate provider for top level tax regions by @fPolic in https://github.com/medusajs/medusa/pull/12450
* fix(core-flows, dashboard): reservation recreation on fulfilment cancel + allocation button display by @fPolic in https://github.com/medusajs/medusa/pull/12447
## Documentation
* docs: fix reference of draft orders JS SDK methods by @shahednasser in https://github.com/medusajs/medusa/pull/12271
* docs: fix core flows reference not generating by @shahednasser in https://github.com/medusajs/medusa/pull/12274
* docs: regenerate core-flows reference + OAS for draft order updates by @shahednasser in https://github.com/medusajs/medusa/pull/12280
* docs: clarify ISO format for province codes by @shahednasser in https://github.com/medusajs/medusa/pull/12282
* docs: add note to s3 guide by @shahednasser in https://github.com/medusajs/medusa/pull/12289
* docs: improve documetation around error handling in workflows by @shahednasser in https://github.com/medusajs/medusa/pull/12288
* docs: added mark fulfillment delivered step in digital products recipe by @shahednasser in https://github.com/medusajs/medusa/pull/12290
* docs-util: enable internal resolve for workflows sdk reference by @shahednasser in https://github.com/medusajs/medusa/pull/12292
* docs: improve resend guide by @shahednasser in https://github.com/medusajs/medusa/pull/12293
* Update 6.3. Using TypeScript Aliases - Alias should run after build, not before by @AlexanderLindkjaer in https://github.com/medusajs/medusa/pull/12272
* docs: general improvements and additions by @shahednasser in https://github.com/medusajs/medusa/pull/12296
* docs: fix troubleshooting page by @shahednasser in https://github.com/medusajs/medusa/pull/12305
* docs-util: add sidebar link validation in prep script by @shahednasser in https://github.com/medusajs/medusa/pull/12306
* docs: fix module name in product review guide by @shahednasser in https://github.com/medusajs/medusa/pull/12310
* docs(algolia): rename instructed filename to fit code-block and preserve naming conflict instructions by @MentorFilou in https://github.com/medusajs/medusa/pull/12300
* docs: improve installation documentation with diagrams by @shahednasser in https://github.com/medusajs/medusa/pull/12312
* docs: fix incorrect note usage in some workflow references by @shahednasser in https://github.com/medusajs/medusa/pull/12317
* docs: fix missing quotation mark in marketplace vendor tutorial curl request by @Obad94 in https://github.com/medusajs/medusa/pull/12315
* docs: localization with contentful guide by @shahednasser in https://github.com/medusajs/medusa/pull/12202
* docs-util: fix hook examples not showing in generated references by @shahednasser in https://github.com/medusajs/medusa/pull/12334
* docs: fix TypeScript errors in marketplace vendor tutorial by @Obad94 in https://github.com/medusajs/medusa/pull/12302
* docs-util: support deprecated tag in OAS by @shahednasser in https://github.com/medusajs/medusa/pull/12339
* docs-util: add script to generate events info by @shahednasser in https://github.com/medusajs/medusa/pull/12340
* docs: generate events reference by @shahednasser in https://github.com/medusajs/medusa/pull/12341
* docs: fix redirect on infrastructural modules by @shahednasser in https://github.com/medusajs/medusa/pull/12358
* docs: fix local links in UI docs by @shahednasser in https://github.com/medusajs/medusa/pull/12359
* docs: add script to catch bad redirects by @shahednasser in https://github.com/medusajs/medusa/pull/12361
* docs: add troubleshooting for index.html error by @shahednasser in https://github.com/medusajs/medusa/pull/12365
* docs: add missing details for tiered pricing by @shahednasser in https://github.com/medusajs/medusa/pull/12374
* docs-util: add events to workflows reference by @shahednasser in https://github.com/medusajs/medusa/pull/12376
* docs: generate event references by @shahednasser in https://github.com/medusajs/medusa/pull/12378
* docs-util: fix hook parameters not showing when using workflow input by @shahednasser in https://github.com/medusajs/medusa/pull/12382
* docs: fixes to navbar and sidebar in mobile by @shahednasser in https://github.com/medusajs/medusa/pull/12379
* docs: update import user guide text + add diagram in brand module guide by @shahednasser in https://github.com/medusajs/medusa/pull/12385
* docs-util: add events to generated OAS by @shahednasser in https://github.com/medusajs/medusa/pull/12390
* docs: show events emitted in an API route in the API reference by @shahednasser in https://github.com/medusajs/medusa/pull/12392
* docs: generate OAS with events by @shahednasser in https://github.com/medusajs/medusa/pull/12394
* docs: added bundled products guide by @shahednasser in https://github.com/medusajs/medusa/pull/12332
* docs: add copy subscriber button by @shahednasser in https://github.com/medusajs/medusa/pull/12405
* docs: generate references after adding copy subscriber button by @shahednasser in https://github.com/medusajs/medusa/pull/12407
* docs: add support for keywords in references by @shahednasser in https://github.com/medusajs/medusa/pull/12413
* docs: add class for header wrapper + keywords for payment guide by @shahednasser in https://github.com/medusajs/medusa/pull/12414
* chore: update Medusa UI packages in docs on new release by @shahednasser in https://github.com/medusajs/medusa/pull/12415
* docs: enable and send algolia events by @shahednasser in https://github.com/medusajs/medusa/pull/12416
* docs: updates to middlewares and protected API routes + new chapter by @shahednasser in https://github.com/medusajs/medusa/pull/12419
* docs: support version in events reference by @shahednasser in https://github.com/medusajs/medusa/pull/12422
* docs-util: add note for providers by @shahednasser in https://github.com/medusajs/medusa/pull/12432
* docs: support showing version of API route in API reference by @shahednasser in https://github.com/medusajs/medusa/pull/12433
* docs: fix keyboard navigation in search by @shahednasser in https://github.com/medusajs/medusa/pull/12434
* docs: support deprecated in API reference by @shahednasser in https://github.com/medusajs/medusa/pull/12438
* docs-util: fix dependencies passed to auth providers by @shahednasser in https://github.com/medusajs/medusa/pull/12445
* Update page.mdx to correct "th" to "the" by @dsvwilson in https://github.com/medusajs/medusa/pull/12446
* docs: added saved payment methods with Stripe tutorial by @shahednasser in https://github.com/medusajs/medusa/pull/12257
## Chores
* chore(js-sdk): fix TSDocs of draft orders in JS SDK by @shahednasser in https://github.com/medusajs/medusa/pull/12270
* chore(core-flows, types): add tsdocs for draft orders workflows by @shahednasser in https://github.com/medusajs/medusa/pull/12279
* chore(types): claify province code format in TSDocs by @shahednasser in https://github.com/medusajs/medusa/pull/12283
* chore(core-flows): fix note usage in TSDocs by @shahednasser in https://github.com/medusajs/medusa/pull/12318
* chore: add tsdocs for events by @shahednasser in https://github.com/medusajs/medusa/pull/12337
* chore(utils): fixes to events TSDocs by @shahednasser in https://github.com/medusajs/medusa/pull/12342
* chore(types): add note in TSDocs of list and retrieve methods by @shahednasser in https://github.com/medusajs/medusa/pull/12364
* feat(workflows-*): Allow to re run non idempotent but stored workflow with the same transaction id if considered done by @adrien2p in https://github.com/medusajs/medusa/pull/12362
* chore(utils): fixes to events TSDocs by @shahednasser in https://github.com/medusajs/medusa/pull/12395
* chore: Minor restructure of cart completion by @olivermrbl in https://github.com/medusajs/medusa/pull/12353
* chore: update generate references action to generate / commit events by @shahednasser in https://github.com/medusajs/medusa/pull/12411
* chore(utils): small fix to payload in TSDocs by @shahednasser in https://github.com/medusajs/medusa/pull/12409
* chore(utils): add version tag to order edit events by @shahednasser in https://github.com/medusajs/medusa/pull/12424
* test(workflow-engine): Ensure failed subscriber does not compensate workflows by @adrien2p in https://github.com/medusajs/medusa/pull/12427
* chore(js-sdk,types,utils): updates to file TSDocs by @shahednasser in https://github.com/medusajs/medusa/pull/12426
* chore(js-sdk, types): update TSDocs related to tax provider changes by @shahednasser in https://github.com/medusajs/medusa/pull/12428
* chore(medusa): add version tag for new routes by @shahednasser in https://github.com/medusajs/medusa/pull/12436
## Other Changes
* docs: improve database operations docs + added data model repository reference by @shahednasser in https://github.com/medusajs/medusa/pull/12273
* feat: internationalize hard-coded strings in product-create-general-section.tsx by @MentorFilou in https://github.com/medusajs/medusa/pull/12264
* test: use jest shards and simplify test-cli-pipeline by @thetutlage in https://github.com/medusajs/medusa/pull/12278
* fix(dashboard): Admin Global Search broken for variants by @AmbroziuBaban in https://github.com/medusajs/medusa/pull/11877
* chore: Update teams.yml by @olivermrbl in https://github.com/medusajs/medusa/pull/12355
* fix: rename Macedonia FYROM to North Macedonia by @edinabazi in https://github.com/medusajs/medusa/pull/12375
* fix: Added missing admin dashboard dependencies by @pepijn-vanvlaanderen in https://github.com/medusajs/medusa/pull/12346
* test(core-flows): Ensure productVariantUpdated failure compensate the workflow by @adrien2p in https://github.com/medusajs/medusa/pull/12381
* fix(plugins, utils): Plugin admin folder loading with backslash on Windows by @Betanoir in https://github.com/medusajs/medusa/pull/12418
## New Contributors
* @AlexanderLindkjaer made their first contribution in https://github.com/medusajs/medusa/pull/12272
* @MentorFilou made their first contribution in https://github.com/medusajs/medusa/pull/12264
* @Obad94 made their first contribution in https://github.com/medusajs/medusa/pull/12315
* @edinabazi made their first contribution in https://github.com/medusajs/medusa/pull/12375
* @Betanoir made their first contribution in https://github.com/medusajs/medusa/pull/12418
* @dsvwilson made their first contribution in https://github.com/medusajs/medusa/pull/12446
**Full Changelog**: https://github.com/medusajs/medusa/compare/v2.7.1...v2.8.0