Releases: medusajs/medusa
v2.12.3: Translations (experimental) and Order Exports
Highlights
Translations (experimental)
This release introduces experimental support for Translations. Translations allows merchants to configure multiple locales in their store and translate their product information accordingly. In this experimental release, translations support all entities from the Product Module. In the official release in January, we expect to support additional core entities and offer framework-level tooling to translate entities from custom modules.
Read the announcement blog post or get started in our documentation.
Order Exports
This release introduces support for exporting Orders to a .csv file from Medusa Admin. The export will use the filters applied in the orders table.
Features
- feat(): Sync order translations by @adrien2p in #14267
- feat: order export and upload stream by @carlos-r-l-rodrigues in #14243
- feat(): Add support for locale to the js sdk by @adrien2p in #14306
- feat(): Add support for store locales end point by @adrien2p in #14307
- feat(): Translation statistics by @adrien2p in #14299
- feat(): Add more translatable core entity by @adrien2p in #14311
- feat(js-sdk,types,medusa): add list locales store method to JS SDK by @shahednasser in #14314
- feat(): remove status from translatable fields by @adrien2p in #14321
- feat: Translations UI by @NicolasGorga in #14217
Bugs
- fix(translation): add index file for models by @shahednasser in #14272
- fix(types,translations): fix types for translation and locale updates by @shahednasser in #14278
- fix(types): add locale to the query parameters of product query types by @shahednasser in #14282
- fix(index): detect enum field by @carlos-r-l-rodrigues in #14298
- fix(link-modules): export store locale link definition by @NicolasGorga in #14293
- Fix/readonly link feature flag conditional by @adrien2p in #14316
- fix(pricing,dashboard): update min_quantity/max_quantity to decimal in price model by @NicolasGorga in #14045
- fix(): Cart translation sync by @adrien2p in #14327
Documentation
- docs: updates for next release by @shahednasser in #14275
- chore(docs): Generated DML JSON files (automated) by @github-actions[bot] in #14284
- docs: update next and react by @shahednasser in #14288
- chore: generate and update OAS for translations by @shahednasser in #14281
- docs: translation module by @shahednasser in #14271
Chores
- chore(docs): Update version in documentation (automated) by @github-actions[bot] in #14283
- chore(docs): Updated UI Reference (automated) by @github-actions[bot] in #14285
- chore: Introduce OIDC auth for npm publishing by @olivermrbl in #14279
- chore(utils): currency epsilon by @carlos-r-l-rodrigues in #14225
- chore(): Allow PR CI to run all the time by @adrien2p in #14295
- chore: sync Figma resources by @fPolic in #14297
- chore(): Remove default_locale from StoreLocale by @NicolasGorga in #14300
- chore(): apply locale middleware to all store routes by @adrien2p in #14305
- chore(): Update locale header usage by @adrien2p in #14318
- chore(): Migration generator fix generated import by @adrien2p in #14315
- chore(): js-sdk set locale in server environment by @adrien2p in #14313
- chore: TSDocs for Translation Module by @shahednasser in #14280
- chore(): Apply translation feature flag broaderly by @adrien2p in #14319
- chore: added since tag to new routes by @shahednasser in #14322
- chore: add missing since tag for js sdk by @shahednasser in #14325
Other Changes
- feat(admin): add translation for zhTW by @Achang0611 in #14124
New Contributors
- @Achang0611 made their first contribution in #14124
Full Changelog: v2.12.2...v2.12.3
v2.12.2: Experimental backend HMR and granular queue configurations
Highlights
Granular queue configurations
This release adds support for configuring the queue and workers of the Redis Workflow Engine (@medusajs/workflow-engine-redis). You can pass any options supported by BullMQ, e.g. concurrency, in the options of the module.
Here's an example configuration:
module.exports = defineConfig({
modules: [
{
resolve: "@medusajs/workflow-engine-redis",
options: {
queueOptions: { defaultJobOptions: { removeOnComplete: 1000 } },
workerOptions: { concurrency: 10 }
},
},
})Core multi-language infrastructure
This release adds the core foundation for multi-language support. We expect to have a first testable preview version some time next week.
The scope of the first release is aimed to solve the following:
- Allow merchants to configure multiple locales for their store
- Allow merchants to add translations for entities in the Product Module
- Allow storefront developers to easily retrieve localized products
- Use translated product data in the cart and order flows, e.g. add item to cart
Although, the first release is only focused on the product-related entities, we have built the infrastructure to enable translations of any entity (core and custom). More on this later.
Backend HMR (experimental)
This release introduces experimental Hot Module Replacement (HMR) for our backend to improve the local development experience. In its current state, this feature is a work-in-progress and should be used with caution.
So far, we have added HMR support for the following files and tools:
- API Routes (and middlewares)
- Workflows & Steps
- Scheduled Jobs
- Event Subscribers
- Modules
As well as regular files, such as types and utilities.
When HMR cannot handle a change, we fallback to restarting the server completely.
You can read more about the architecture and key features here: #14074
How to enable it
The feature is behind a feature flag. Enable it by setting:
// medusa-config.ts
module.exports = defineConfig({
featureFlags: {
backend_hmr: true
}
})Features
- feat(dashboard): Improve fully refunded order details by @NicolasGorga in #14077
- feat(): Introduce translation module and preliminary application of them by @adrien2p in #14189
- feat(): sync cart translation synced by @adrien2p in #14226
- chore(): Add translations/locale integration tests and fix locale endpoint by @adrien2p in #14266
- feat(): Pluralized props for list readonly link by @adrien2p in #14190
Bugs
- chore(): revert route loading parallelization by @adrien2p in #14204
- fix S3 URL escaping by @peterlgh7 in #14220
- fix(dashboard): show correct color indicators for payment and fulfillment status columns for
view_configurationfeature flag by @NicolasGorga in #14215 - fix(core-flows): refresh payment collection inside updateCartPromotionsWorkflow by @NicolasGorga in #13963
- fix(dashboard): avoid unnecessary product relations to be returned by default by @NicolasGorga in #14175
- fix(utils): fix error when generating migrations for a module with existing snapshot by @shahednasser in #14218
- fix(medusa): use customer query config on delete address route by @NicolasGorga in #14238
- fix(dashboard,order): preview pending diff summary by @fPolic in #14221
- fix(dashboard): pass prefix to useDataTable to fix product list not paginating by @NicolasGorga in #14232
- fix(core-flows): Access orderItem.variant safely inside convertDraftOrderWorkflow when containing custom items by @NicolasGorga in #14233
- fix(utils): avoid inflating refundable_total for tax inclusive pricing by @NicolasGorga in #14237
- chore(): Upgrade validator patched version by @adrien2p in #14254
- fix(): Improve store supported locale -> locale readonly link by @adrien2p in #14269
- fix(utils,core-flows): add events constant for translations and use it in workflows by @shahednasser in #14277
- fix(core-flows): refresh payment collection inside updateCartPromotionsWorkflow (patch) by @NicolasGorga in #14274
Documentation
- chore(docs): Generated References (automated) by @github-actions[bot] in #14199
- docs: add best practices doc for third-party syncing by @shahednasser in #14203
- docs: add custom admin route ranking documentation by @bqst in #13984
- docs: update Next.js + React by @shahednasser in #14210
- chore(docs): Updated UI Reference (automated) by @github-actions[bot] in #14212
- docs: triage issues + revamp troubleshooting guides by @shahednasser in #14216
- docs: okta integration tutorial by @shahednasser in #14188
- docs: various improvements and fixes by @shahednasser in #14257
- docs: improve build with AI chapter by @shahednasser in #14259
Chores
- chore(docs): Update version in documentation (automated) by @github-actions[bot] in #14198
- chore(docs): Updated API Reference (automated) by @github-actions[bot] in #14200
- chore: configurable database migration in concurrency by @carlos-r-l-rodrigues in #14004
- chore(): Run some commands in server mode only by @adrien2p in #14202
- chore(event-bus, workflow-engine): Enable more granualar queues configuration by @adrien2p in #14201
- Add js-sdk to resolutions in local development section by @NicolasGorga in #14197
- chore: improvements of TSDocs of link steps by @shahednasser in #14261
- chore(): Move event bus local logging by @adrien2p in #14244
- chore(): Accept an extra agument 'all-or-nothing' on the migrate command by @adrien2p in #14262
- chore(order): Remove unique index on item_id:version for order_item by @NicolasGorga in #14268
- chore: Add locks to order edit flows by @olivermrbl in #14270
Other Changes
- escape non-ascii characters in filenames in s3 file provider by @peterlgh7 in #14209
- chore: Backend HMR (expriemental) by @adrien2p in #14074
- fix(core-flows, medusa): Prevent cart addresses duplication on update by @NicolasGorga in #13841
Full Changelog: v2.12.1...v2.12.2
v2.12.1: Fix regression in events system
Highlights
This release fixes a regression in the events system introduced in #14084. That PR added an optimization to emit events only when at least one subscriber is registered for the event.
However, this unintentionally broke instances running in server mode. Historically, server instances have not registered subscribers, only worker instances have. With the new optimization, these instances incorrectly determined that no subscribers existed for all emitted events and therefore skipped emission entirely.
As a result, applications running version 2.12.0 in server mode have effectively emitted no events.
If you have already upgraded to 2.12.0 and are using server instances, we strongly recommend validating whether any critical events have been missed since the upgrade and, if necessary, processing them manually.
This release also contains a migration, so you need to run the migration script after upgrading:
npx medusa db:migrate
Bugs
- fix(order): Add composite unique index on order_item version:item_id by @NicolasGorga in #14164
- fix(): event emitting by @adrien2p in #14196
Documentation
- docs: docs for next release by @shahednasser in #14110
- chore(docs): Generated DML JSON files (automated) by @github-actions[bot] in #14180
- chore(docs): Updated UI Reference (automated) by @github-actions[bot] in #14181
- chore(docs): Generated References (automated) by @github-actions[bot] in #14182
- docs: generate API reference for 2.12.0 by @shahednasser in #14185
- docs: strapi integration guide by @shahednasser in #14075
- docs: track code copy + AI assistant event by @shahednasser in #14193
- docs: improve CORS troubleshooting guide by @shahednasser in #14194
Chores
- chore(docs): Update version in documentation (automated) by @github-actions[bot] in #14179
- chore: fixes to TSDocs by @shahednasser in #14186
Full Changelog: v2.12.0...v2.12.1
2.12.0: New Promotion limit, custom display ID on orders, improved event management
Highlights
This release introduces migrations, so remember to run migrations after installing the version:
npx medusa db:migrate
In addition to migrations with schema changes, this release also runs a data migration script added in this PR. The script populates a new version column on order line item adjustments, setting it to the latest version of the associated order.
Custom order display ID
This release introduces a custom_display_id field on orders, along with a hook for automatically generating the value at order creation.
The key changes are:
- New
custom_display_idcolumn on orders - Order Module now accepts a
generateCustomDisplayIdfunction in its module options
The generation can be used like so:
// medusa-config.ts
defineConfig({
// ...
modules: [{
resolve: "@medusajs/medusa/order",
options: {
generateCustomDisplayId: async function (order: OrderTypes.CreateOrderDTO, sharedContext: Context) {
// Return your custom display id
}
}
}]
})We intentionally kept the existing display_id column unchanged. Migrating it from an auto-incrementing integer to text would be a significant breaking change.
To show the new custom_display_id in the Admin dashboard, you can use the View Configurations feature to customize columns on the order table:
// medusa-config.ts
defineConfig({
// ...
featureFlags: {
view_configurations: true
}
})Promotion limit
This release expands promotion configuration capabilities by introducing a limit enforced on promotions. Previously, limits could only be enforced at the campaign level. You can now configure limits at three levels:
- Campaign-level: limit the number of times a certain promotion in a campaign can be used
- Campaign-level per customer/email: limit the number of times a certain promotion in a campaign can be used by a specific customer or email
- Promotion-level: limit the number of times a certain promotion can be used
Promotions on exchanges
This release adds the option to carry over promotions to exchanges on orders. When creating an exchange, you often want the original promotions applied to the outbound items to avoid recharging the customer. You can now opt into this by enabling "Carry over promotions" during the exchange flow.
Admin user deletion
This release adds the ability for admin users to delete other users. This is a temporary solution ahead of a proper permissions system, which we plan to work on in the near future.
Limiting event emission
This release improves event management, reducing unnecessary memory and processing overhead by only emitting events and adding to event queues whenever there are subscribers to the events.
Shipping Option Type relation
Breaking change
The relationship between Shipping Options and Shipping Option Types has changed from one-to-one to many-to-one. This change should be deemed more a fix, than an actual change of the feature, as this was always the intention. However, it is a breaking change, since the property name has changed.
Features
- feat(dashboard): Improve error messages during file upload by @juanzgc in #13991
- feat(medusa): allow users deletion by @NicolasGorga in #13960
- feat(dashboard): include product material in product general section by @NicolasGorga in #14021
- feat(promotion): Add metadata column to promotion by @juanzgc in #13999
- feat(dashboard): show promo tooltip on the edit flows by @fPolic in #14121
- feat: carry over promotions toggle on exchanges by @fPolic in #14128
- feat: promotion usage limit by @fPolic in #13760
Bugs
- fix(dashboard): fix import for ptPT locale by @willbouch in #13986
- fix(dashboard): Limit file uploads to 1MB by @juanzgc in #13981
- fix(core-flows,types): change doc for upload file functions by @willbouch in #13809
- fix(): Lock process payment to prevent ingesting payment processing t… by @adrien2p in #13977
- fix(dashboard): update orders page filters to match interface expected by old DataTable component by @NicolasGorga in #13994
- fix(product, types): add missing types for variant images and thumbnails by @shahednasser in #14026
- fix(dashboard): use order version 1 for the initial node of activity timeline by @NicolasGorga in #13997
- fix(medusa): preprocess
versionas number in AdminGetOrdersOrderParams validator by @NicolasGorga in #13996 - fix(): Proper schema usage when running migrations by @adrien2p in #14036
- fix(draft-order): Update copy phone number by @juanzgc in #14044
- fix(): Identify step that should require a save on checkpoint by @adrien2p in #14037
- fix(dashboard): reference global vite bin from scripts by @fPolic in #14049
- fix(core-flows): avoid overriding customer and region from setPricingContext hook result by @NicolasGorga in #14022
- fix(payment): Double idempotent capture called with auto capture beha… by @adrien2p in #14073
- chore(): Update glob package by @adrien2p in #14083
- fix(medusa): avoid throwing on error on set step failure endpoint by @NicolasGorga in #14066
- fix(core-flows): prevent completing cart from webhook when order already exists by @NicolasGorga in #14108
- fix(core-flows): Add discountable properties in queried fields to avoid overriding discountable properties when set by @NicolasGorga in #14105
- fix(): Workflow engine redis worker instance in worker mode by @adrien2p in #14099
- fix(product): add missing decorators to updateProductOptionValues method by @shahednasser in #14060
- fix: Compute "virtual" adjustments for order previews by @olivermrbl in #13306
- fix(core-flows): lock mark as delivered fulfillment/order flows by @NicolasGorga in #14111
- fix(orchestration): fetch fields from link entities by @carlos-r-l-rodrigues in #14097
- fix(js-sdk,types,medusa): add HTTP types for update order change API route by @shahednasser in #14169
- fix(core-flows): create reservations on draft order conversion to regular order by @NicolasGorga in #14010
- fix(fulfillment): make relationship between SO and SO type M:1 by @fPolic in #14061
- fix(product): Update performance issue by @adrien2p in #14150
Documentation
- chore(docs): Updated UI Reference (automated) by @github-actions[bot] in #13968
- docs: fix command bar position outside modal in category images guide by @shahednasser in #13987
- docs: fix broken links in OAS by @shahednasser in #14000
- docs-utils: fix type error in react-docs-generator by @shahednasser in #14002
- docs: add missing middlewares in category images tutorial by @shahednasser in #14001
- docs: added kapa logo + link to mcp server by @shahednasser in #14005
- docs: add JSON-LD schemas to docs by @shahednasser in #14007
- docs: generate OAS for 2.11.3 by @shahednasser in #13973
- docs: mobile app guide with react native and expo by @shahednasser in #13982
- fix some typos by @dhanushreddy291 in #14017
- docs: add a copy button to AI assistant answers by @shahednasser in #14052
- docs: fix required properties marked as optional in OAS with allOf schemas by @shahednasser in #14062
- docs: add redis prerequisite for Caching Module by @shahednasser in #14051
- docs: emails in cloud by @shahednasser in #14040
- docs: fix filters in meilisearch and algolia guides by @shahednasser in #14098
- docs: updates to billing details by @shahednasser in #14096
- docs: fix callback validation for third-party authentication by @shahednasser in #14109
- docs: customer tiers tutorial by @shahednasser in https://github.com/medusajs/medusa/pul...
v2.11.3: Dependency clean-up
Highlights
Dependency clean-up and restructuring
This release comes with a major clean-up of dependencies used across our packages.
The clean-up includes 1) replacing large dependencies with native code to reduce bundle size, 2) ensuring unified dependency versions across packages, and 3) eliminating security vulnerabilities from dependencies.
As a result of these changes, the production node_modules have been reduced from 1GB+ → 837MB (approx. -16%), and we are down to a single low security vulnerability.
You can read more about the changes in #13932, #13910, and #13940.
Features
- feat(dashboard): include missing columns import template by @NicolasGorga in #13958
Bugs
- fix: Updates to medusa payments provider by @sradevski in #13914
- fix(): update Integration test enabling index when not necessary by @adrien2p in #13904
- chore(): Fix dependencies by @adrien2p in #13932
- fix: Update type Providers by @juanzgc in #13927
- fix opentelemetry-resources dependency typo by @peterlgh7 in #13948
- fix(types, medusa): fixes to http types and validators by @shahednasser in #13928
- Remove fetchPreviousPage/fetchNextPage from dependency array of useEf… by @NicolasGorga in #13949
- fix(medusa): priced products region_id regression by @NicolasGorga in #13961
- fix(): Index integration tests flackyness by @adrien2p in #13953
Documentation
- docs: docs for next release by @shahednasser in #13907
- chore(docs): Generated DML JSON files (automated) by @github-actions[bot] in #13919
- docs: document asymmetric encryption by @shahednasser in #13922
- docs: clarify prices are stored in major units by @shahednasser in #13897
- chore(docs): Generated References (automated) by @github-actions[bot] in #13921
- docs: generate OAS for 2.11.2 by @shahednasser in #13925
- docs: fix deployment error by @shahednasser in #13942
- docs: fix broken image in billing docs + clarify billing details by @shahednasser in #13944
- docs: fixes to recipes and examples following latest update by @shahednasser in #13933
- Include expected Sentry opentelemetry 1.x peer deps by @NicolasGorga in #13947
- docs: add keywords to Cloud sign up guide by @shahednasser in #13950
- docs: added product rental tutorial by @shahednasser in #13896
- docs: refactor analytics + remove segment by @shahednasser in #13954
Chores
- chore(docs): Update version in documentation (automated) by @github-actions[bot] in #13918
- chore(docs): Updated UI Reference (automated) by @github-actions[bot] in #13920
- chore(modules-sdk): parallel migrations by @carlos-r-l-rodrigues in #13898
- chore: add missing since and featureFlag tags by @shahednasser in #13926
- chore(): Update dependencies usage by @adrien2p in #13910
- chore(medusa): do not use transaction id on cart operations by @carlos-r-l-rodrigues in #13931
- chore(): Cleanup and organize deps by @adrien2p in #13940
- chore(): Update root dev deps and Stabilize package integration tests pipeline by @adrien2p in #13952
- chore(modules-sdk): db migration concurrency as envvar by @carlos-r-l-rodrigues in #13965
Other Changes
- Quote column names in indexes by @peterlgh7 in #13938
- Inject config module in tests by @peterlgh7 in #13937
- Version Packages by @github-actions[bot] in #13923
Full Changelog: v2.11.2...v2.11.3
v2.11.2: Product variant images and Index management API
Highlights
Product variant images
This release introduces images on product variants. It is now possible to assign images to individual product variants, enabling fully scoped variant-specific photos. In addition to this, a variant can have a thumbnail among its associated images.
The behavior of images is as follows:
- Images are added to products
- Variant images are chosen among the product images
- Upon retrieving variants, the variant images will contain:
- Product images that are not associated with any variants
- Images that are associated with the variant
For example, let's imagine you have three product images:
- White t-shirt
- Black t-shirt
- T-shirt on a model
You want to share the third image across variants, and have the white image on the white variants and black image on the black variants. To achieve this, you associate the white t-shirt image with the white variants, and the black t-shirt image with the black variants. The third image should have no associated variants.
This in turn would result in the following response on variants:
{
"id": "prod_1234",
"variants": [
{
"id": "var_1234",
"title": "White t-shirt"
"images": [
{ "id": "img_1234", "url": "http://images.com/white-t-shirt.png" },
{ "id": "img_1234", "url": "http://images.com/t-shirt-on-model.png" }
]
},
{
"id": "var_4321",
"title": "Black t-shirt"
"images": [
{ "id": "img_1234", "url": "http://images.com/black-t-shirt.png" },
{ "id": "img_1234", "url": "http://images.com/t-shirt-on-model.png" }
]
},
]
}Managing variant images
Two endpoints have been added:
POST /admin/products/:id/variants/:variant_id/images/batch— Batch manage image associations for a specific variant.POST /admin/products/:id/images/:image_id/variants/batch— Batch manage variant associations for a specific image.
Admin UI
You can manage product variant images from the product page in the admin dashboard. There are two ways to manage these.
From the root-level product page, you can associate a single image with many variants:
From the variant-specific page, you can associate many images with a single variant:
Data model changes
The following are changes to the data models in the Product Module required to enable this feature:
- ProductVariant now includes a many-to-many relationship with ProductImage.
- A new ProductVariantProductImage pivot entity manages these associations.
Therefore, please make sure to run migrations after upgrading to the new version:
npx medusa db:migrateIndex management API
This release adds a new API for managing the index, enabling you to trigger synchronization and retrieve detailed information about the last sync. The update improves visibility and control over the indexing process.
API
GET /admin/index/details— Retrieve index metadata, including entity type, status, last synced key, and last update timestamp.POST /admin/index/sync— Trigger synchronization from last synced data- Supports optional options:
{ strategy: "full" }— Perform a full sync{ strategy: "reset" }— Truncate tables and perform a fresh sync.
- Supports optional options:
Faster price updates
This release brings performance improvements to the Pricing Module, significantly speeding up price list and price set updates. The changes focus on optimizing database queries, reducing redundant computations, and streamlining price normalization and upsert operations.
Features
- feat(core-flows,product,types): scoped variant images by @fPolic in #13623
- feat(medusa,types): product variant store endpoints by @fPolic in #13730
- feat(product): build variant images when retrieving product by @fPolic in #13731
- feat(index): Add http/module api to interact with the index engine by @adrien2p in #13869
- feat: Implement medusa payments provider by @sradevski in #13772
- feat(dashboard): variant images list thumbnail + refactor form state management by @fPolic in #13905
Bugs
- use truncate in db teardown by @peterlgh7 in #13875
- fix(dashboard): preserve old image ids when deleting a product image by @fPolic in #13881
- fix(pricing): price list prices perf issues by @adrien2p in #13899
- chore(): Generate migrations with correct mikro orm import path by @adrien2p in #13893
- fix: allow controlling hmr bind host by @srindom in #13692
- fix(utils): db migration big number default value by @carlos-r-l-rodrigues in #13913
- chore(): Throw on migration up/down fail by @adrien2p in #13911
Documentation
- docs: fix spelling and grammar by @MBLVD in #13862
- docs: documented admin translations by @shahednasser in #13864
- docs: fix runtime error occuring with code tabs by @shahednasser in #13873
- Add PG_CONNECTION to Medusa Container docs by @NicolasGorga in #13871
- docs: fix mikro-orm imports from framework by @shahednasser in #13885
- docs: category images guide by @shahednasser in #13755
- docs: fix category images guide by @shahednasser in #13908
- docs: serve markdown to AI agents by @shahednasser in #13915
- docs: updated user stories in /learn by @cboeddek in #13866
Chores
- chore(docs): Update version in documentation (automated) by @github-actions[bot] in #13854
- chore(docs): Generated DML JSON files (automated) by @github-actions[bot] in #13855
- chore(docs): Updated UI Reference (automated) by @github-actions[bot] in #13856
- chore(docs): Generated References (automated) by @github-actions[bot] in #13857
- chore: fixes to http and request types for products by @shahednasser in #13833
- chore: fixes to HTTP and request types for API Keys by @shahednasser in #13819
- chore: fixes to HTTP and request types for promotions by @shahednasser in #13820
- chore: fixes to HTTP and request types for carts by @shahednasser in #13821
- chore: fixes to http and request types for orders (2) by @shahednasser in #13823
- chore: fixes to http and request types for orders (3) by @shahednasser in #13824
- chore: fixes to http and request types for customers by @shahednasser in #13825
- chore: fixes to http and request types for fulfillment by @shahednasser in #13826
- chore: fixes to http and request types for inventory by @shahednasser in #13827
- chore: fixes to http and request types for users by @shahednasser in #13828
- chore: fixes to http and request types for payments by @shahednasser in #13830
- chore: fixes to http and request types for payment and regions by @shahednasser in #13831
- chore: fixes to http and request types for sales channes, taxes, and store by @shahednasser in #13832
- chore: fixes to http and request types for orders (1) by @shahednasser in #13822
- chore: Inject sandbox handle in cloud config by @olivermrbl in #13879
- chore(types,notification): Make template nullable on emails by @olivermrbl in #13889
Other Changes
- add Medusa Cloud Email provider by @peterlgh7 in #13781
- feat(dashboard): add input field for tracking_url and label_url in shipment form by @kevinresol in #13787
- fix(dashboard): Resolve issue with product attributes input by @siddarthan007 in #13863
- fix(dashboard): tax region override too large payload by @NicolasGorga in #13860
- fix(admin): fix admin promotion list sort by @bqst in #13872
- feat(admin): change admin order list default sort by @bqst in #13874
- fix(dashboar...
v2.11.1
Highlights
Fixes regression with listing price preferences
Adds version to credit lines
This version adds column version to order credit lines and is used for keeping track of credit lines during order edits.
This addition comes with a migration, so after upgrading run the following command to apply it:
npx medusa db:migrate
Features
- feat(order,dashboard): version order credit lines by @willbouch in #13766
Bugs
- fix(test-utils): Duplicated subscribers re insertion by @adrien2p in #13798
- fix: prevent jobId collisions on workflow step retries by @srindom in #13786
- fix(medusa): images recreate on product update by @fPolic in #13813
Documentation
- chore(docs): Updated API Reference (automated) by @github-actions[bot] in #13794
- docs: fixes to API and JS SDK references by @shahednasser in #13795
- docs: fixes to type errors in guides by @shahednasser in #13797
- docs: change Medusa Cache setup information by @shahednasser in #13802
- docs: fix text in payload guide by @shahednasser in #13815
- docs: change binary encoding to base64 in file upload references by @shahednasser in #13811
- docs: add cache to comparison document + pricing fixes by @shahednasser in #13812
- docs: avalara integration tutorial by @shahednasser in #13808
- docs-util: remove inferring of query parameters by @shahednasser in #13834
- docs: clarify how emitEventStep emits an event in a workflow by @shahednasser in #13836
- docs: add error page by @shahednasser in #13839
- docs: improvements to tax related docs by @shahednasser in #13845
- docs: show possible similar pages on 404 page by @shahednasser in #13840
- docs: fixes to docker installation guide by @shahednasser in #13847
- docs: updates to installation doc by @shahednasser in #13848
Chores
- chore(docs): Update version in documentation (automated) by @github-actions[bot] in #13791
- chore(docs): Generated References (automated) by @github-actions[bot] in #13793
- chore(docs): Generated DML JSON files (automated) by @github-actions[bot] in #13790
- chore(docs): Updated UI Reference (automated) by @github-actions[bot] in #13792
- chore: fixes to refund reasons tsdocs by @shahednasser in #13796
- chore(workflow-engine-*): cleanup and improvements by @adrien2p in #13789
- chore: update description of emitEventStep by @shahednasser in #13838
- chore: improve TSDocs for tax provider module by @shahednasser in #13846
Other Changes
- fix(): Remove redundant indexes to resolve schema warnings by @DDA1O1 in #13736
- feat(payment-stripe): merge custom metadata along with session_id on payment initiation by @vethan in #13801
- Added shipping method data to tax module context by @pepijn-vanvlaanderen in #13747
- fix(js-sdk): add missing query param to deleteLineItem jsdoc by @andershermansen in #13835
- feat(admin-*,dashboard): add dashboard i18n extensions by @leobenzol in #13763
New Contributors
- @DDA1O1 made their first contribution in #13736
- @andershermansen made their first contribution in #13835
Full Changelog: v2.11.0...v2.11.1
v2.11.0: Caching primitives, manual refunds, and improved promotion limits
Highlights
Caching layer
This release adds new caching primitives to Medusa's toolbox.
1. New caching module, @medusajs/caching
We have added a new caching module in early preview with strong tools to integrate a cache into your Medusa application. The module comprises three key elements:
- Cache service: the main module service with a simple API for interacting with the cache
- Cache provider: the provider service responsible for delegating operations to the configured cache provider
- Cache strategy: the strategy responsible for computing cache keys and invalidation tags
Cache invalidation
Knowing when and how to invalidate cache entries is a challenging task. With the new caching module, we have baked this logic directly into the tooling, so you don't have to manage the complexity yourself.
We plan to share a technical deep dive covering the invalidation mechanism in detail, but here's the short version: whenever entries are inserted, the cache strategy computes tags based on the data. Invalidation of these entries relies on internal module events emitted whenever mutational service methods are called, e.g. service.update({ ... }). The cache strategy intercepts these events, computes the relevant tags using the event data, and instructs the cache provider to clear all entries associated with those tags.
Read more about this in our documentation.
2. New Redis caching provider, @medusajs/caching-redis
As described above, the new caching module follows our existing provider architecture, allowing different technologies to be used interchangeably without affecting the core application. In this release, we’ve introduced a Redis caching provider, which integrates directly with the caching module and serves as the underlying storage layer for the cached data.
3. New cache option on Medusa Query
Finally, to use the cache, we have introduced a new cache option in our query.graph API:
const { data } = await query.graph({
entity: "product",
filters: { id: "prod_1234" },
options: { cache: { enable: true } }
})This new option allows you to leverage the full power of the cache without having to think about computing keys and invalidation tags. These are automatically computed when query.graph is configured to use the cache.
Installation
Since the caching module is still in early preview, you need to enable a feature flag to use it in addition to registering the Redis cache provider in your medusa-config.ts. The new packages come pre-installed in the latest version of @medusajs/medusa.
// medusa-config.ts
module.exports = defineConfig({
projectConfig: { ... },
modules: [
{
resolve: "@medusajs/medusa/caching",
options: {
providers: [
{
id: "caching-redis",
resolve: "@medusajs/caching-redis",
options: {
redisUrl: process.env.REDIS_URL,
},
},
],
},
},
],
featureFlags: {
caching: true,
},
});By default, the cache is integrated across several business-critical APIs to boost performance and throughput. This includes all cart-related operations, where we cache the following data:
- Regions
- Promotion codes
- Variant price sets
- Variants
- Shipping options
- Sales channels
- Customers
With caching enabled, we’ve observed performance improvements of up to 70% across these operations. Read our blog post
for detailed benchmarks across different Medusa versions.
Bear in mind, our new caching tools are in preview, so they should be used with caution.
Bundle core Medusa dependencies
Breaking change
This release restructures the required dependencies of Medusa projects. We are consolidating all non-Medusa dependencies into a new @medusajs/deps package, which is installed internally in @medusajs/medusa. We are making this change to take control over our core dependencies. This will enable us to add new dependencies and do minor/major upgrades of core dependencies without breaking users' applications.
This is a breaking change, and the following steps are required to use versions 2.11.0 and over:
- Remove the following packages from dependencies in your
package.json:
"dependencies": {
"@medusajs/admin-sdk": "2.11.0",
"@medusajs/cli": "2.11.0",
"@medusajs/framework": "2.11.0",
"@medusajs/medusa": "2.11.0",
- "@mikro-orm/core": "6.4.3",
- "@mikro-orm/knex": "6.4.3",
- "@mikro-orm/migrations": "6.4.3",
- "@mikro-orm/postgresql": "6.4.3",
- "awilix": "^8.0.1",
- "pg": "^8.13.0"
},
"devDependencies": {
"@medusajs/test-utils": "2.11.0",
- "@mikro-orm/cli": "6.4.3",
...- Install dependencies using your preferred package manager
- Run the included codemod (see section below)
- Start your application. If you have issues, please open a GitHub Issue and we will help you out as soon as possible
Codemod
By side effect, this update also requires you to update explicit imports from these dependencies in your own project. To help you with this, we have included a codemod that automatically replaces imports throughout your codebase.
To use the codemod, create a file replace-imports.js in the root of your Medusa application with the following content
Codemod
#!/usr/bin/env node
const fs = require("fs")
const path = require("path")
const { execSync } = require("child_process")
/**
* Script to replace imports and require statements from mikro-orm/{subpath}, awilix, and pg
* to their @medusajs/framework equivalents
*/
// Define the replacement mappings
const replacements = [
// MikroORM imports - replace mikro-orm/{subpath} with @medusajs/framework/mikro-orm/{subpath}
{
pattern: /from\s+['"]@?mikro-orm\/([^'"]+)['"]/g,
// eslint-disable-next-line quotes
replacement: 'from "@medusajs/framework/mikro-orm/$1"',
},
// Awilix imports - replace awilix with @medusajs/framework/awilix
{
pattern: /from\s+['"]awilix['"]/g,
// eslint-disable-next-line quotes
replacement: 'from "@medusajs/framework/awilix"',
},
// PG imports - replace pg with @medusajs/framework/pg
{
pattern: /from\s+['"]pg['"]/g,
// eslint-disable-next-line quotes
replacement: 'from "@medusajs/framework/pg"',
},
// OpenTelemetry imports - replace @opentelemetry/instrumentation-pg, @opentelemetry/resources,
// @opentelemetry/sdk-node, and @opentelemetry/sdk-trace-node with @medusajs/framework/opentelemetry/{subpath}
{
pattern: /from\s+['"]@?opentelemetry\/(instrumentation-pg|resources|sdk-node|sdk-trace-node)['"]/g,
// eslint-disable-next-line quotes
replacement: 'from "@medusajs/framework/opentelemetry/$1"',
},
// MikroORM require statements - replace require('@?mikro-orm/{subpath}') with require('@medusajs/framework/mikro-orm/{subpath}')
{
pattern: /require\s*\(\s*['"]@?mikro-orm\/([^'"]+)['"]\s*\)/g,
// eslint-disable-next-line quotes
replacement: 'require("@medusajs/framework/mikro-orm/$1")',
},
// Awilix require statements - replace require('awilix') with require('@medusajs/framework/awilix')
{
pattern: /require\s*\(\s*['"]awilix['"]\s*\)/g,
// eslint-disable-next-line quotes
replacement: 'require("@medusajs/framework/awilix")',
},
// PG require statements - replace require('pg') with require('@medusajs/framework/pg')
{
pattern: /require\s*\(\s*['"]pg['"]\s*\)/g,
// eslint-disable-next-line quotes
replacement: 'require("@medusajs/framework/pg")',
},
// OpenTelemetry require statements - replace require('@opentelemetry/instrumentation-pg'),
// require('@opentelemetry/resources'), require('@opentelemetry/sdk-node'), and
// require('@opentelemetry/sdk-trace-node') with require('@medusajs/framework/opentelemetry/{subpath}')
{
pattern: /require\s*\(\s*['"]@?opentelemetry\/(instrumentation-pg|resources|sdk-node|sdk-trace-node)['"]\s*\)/g,
// eslint-disable-next-line quotes
replacement: 'require("@medusajs/framework/opentelemetry/$1")',
},
]
function processFile(filePath) {
try {
const content = fs.readFileSync(filePath, "utf8")
let modifiedContent = content
let wasModified = false
replacements.forEach(({ pattern, replacement }) => {
const newContent = modifiedContent.replace(pattern, replacement)
if (newContent !== modifiedContent) {
wasModified = true
modifiedContent = newContent
}
})
if (wasModified) {
fs.writeFileSync(filePath, modifiedContent)
console.log(`✓ Updated: ${filePath}`)
return true
}
return false
} catch (error) {
console.error(`✗ Error processing ${filePath}:`, error.message)
return false
}
}
function getTargetFiles() {
try {
// Get the current script's filename to exclude it from processing
const currentScript = path.basename(__filename)
// Find TypeScript/JavaScript files, excluding common directories that typically don't contain target imports
const findCommand = `find . -name node_modules -prune -o -name .git -prune -o -name dist -prune -o -name build -prune -o -name coverage -prune -o -name "*.ts" -print -o -name "*.js" -print -o -name "*.tsx" -print -o -name "*.jsx" -print`
const files = execSync(...v2.10.3: View configurations and Shipping Options context hook
Highlights
[Experimental] Customizable columns in Medusa Admin tables
In previous versions, tables that list Orders, Products, etc., had hard-coded columns that couldn’t be modified. However, columns have different relevance between businesses. The only way to get tables to show additional columns was to introduce admin extensions that duplicated the original table’s behavior. This was tedious and clunky.
In this release, we are rolling out experimental support for View Configurations, which allow you to change which columns are displayed in the Orders and Products tables. Click the columns dropdown to see the available columns and add the ones you want. The available columns are computed using Medusa’s module graph, meaning any custom data models linked to Orders or Products can also be included in your table config.
With the View Configurations feature, we also enable saved views so you can have the right view at hand for your workflow. Saved views hold both your column configurations and any filters you have applied.
To try View Configurations turn on the feature flag in your medusa-config.ts
module.exports = defineConfig({
...
featureFlags: {
view_configurations: true
}
})Shipping options context hook
This release introduces a hook to customize the context used to list shipping options, allowing you to leverage custom rules for shipping options more easily.
The hook can be used like so:
import { listShippingOptionsForCartWithPricingWorkflow } from "@medusajs/medusa/core-flows"
import { StepResponse } from "@medusajs/workflows-sdk"
listShippingOptionsForCartWithPricingWorkflow.hooks.setShippingOptionsContext(
async ({ cart }, { container }) => {
if (cart.customer_id) {
return new StepResponse({
customer_id: cart.customer_id,
})
}
const query = container.resolve("query")
const { data: carts } = await query.graph({
entity: "cart",
filters: {
id: cart.id,
},
fields: ["customer_id"],
})
return new StepResponse({
customer_id: carts[0].customer_id,
})
}
)In the example above, we add customer_id to the context along with the fixed properties is_return and enabled_in_store. This means that if a shipping option rule includes a customer_id attribute, the shipping option will be included in the result set.
The hook has been introduced in the following workflows:
listShippingOptionsForCartWithPricingWorkflowlistShippingOptionsForCartWorkflow
Please make sure to register the hook in both, since they are used for shipping option validation across workflows.
Features
- feat(medusa): allow filtering by id for collections by @willbouch in #13495
- feat(dashboard): reusable config datatable by @srindom in #13389
- feat(core-flows): hook to set shipping opt context when listing by @willbouch in #13468
- Feat(): promo prefilter top level rules in db by @adrien2p in #13524
- feat(dashboard): configurable product views by @srindom in #13408
Bugs
- fix(): pipeline missing suites by @adrien2p in #13457
- fix(types): cart item totals optional by @willbouch in #13509
- fix(types): pluralize words ending in s like status by @willbouch in #13461
- fix(medusa): Use the correct boolean validator by @adrien2p in #13510
- fix(core-flows, medusa): don't allow negative line item quantity by @fPolic in #13508
- fix(utils,core-flows): subtotal calculation and returns location by @carlos-r-l-rodrigues in #13497
Documentation
- chore(docs): Generated References (automated) by @github-actions[bot] in #13492
- docs: add manage promotions in cart storefront guide by @shahednasser in #13483
- chore: update API reference for 2.10.2 by @shahednasser in #13499
- docs: general improvements and updates by @shahednasser in #13485
- docs: regenerate core-flows reference to pick up locking steps by @shahednasser in #13502
- docs: documentation updates for v2.10.2 by @shahednasser in #13500
- docs: fix issues in product builder tutorial by @shahednasser in #13505
- docs: add clarification for set cart's customer API route by @shahednasser in #13506
- docs: add section on retrieve totals for cart items and shipping methods in storefront by @shahednasser in #13513
- docs: general improvements and fixes by @shahednasser in #13515
- docs: small update to invoice generator introduction by @shahednasser in #13519
- docs: add Next.js starter guides to llms-full.txt by @shahednasser in #13523
- docs: fixes to JS SDK + auth provider guides by @shahednasser in #13526
- docs: general improvements by @shahednasser in #13530
- docs: improve third-party auth in storefront guide by @shahednasser in #13534
Chores
- chore(docs): Updated UI Reference (automated) by @github-actions[bot] in #13491
- chore(docs): Update version in documentation (automated) by @github-actions[bot] in #13490
- chore(js-sdk): add ignore tag to views by @shahednasser in #13503
- chore: update TSDocs of JS SDK store methods to clarify required auth by @shahednasser in #13507
- chore(core-flows): use directory convention for locking steps by @shahednasser in #13501
- chore: add a link to the storefront docs for cart item totals type by @shahednasser in #13514
- test(): test dynamic max workers and improve CI by @adrien2p in #13516
- chore(): Shard unit tests jobs by @adrien2p in #13525
- fix(core-flows): Lock cart on shipping + taxes update by @olivermrbl in #13535
- chore: add tsdocs for latest changes by @shahednasser in #13539
- fix(): Prevent promotion filtering to exceed psql limits by @adrien2p in #13540
Other Changes
- fix(js-sdk): skip null values in query qs.stringify by @leobenzol in #13460
- feat(dashboard): update display of tracking/label URLs on order details by @docloulou in #11613
- fix(dashboard): added missing currencies by @tehaulp in #13214
- test(): Try to reproduce automatic promotion adjustments being applied twice by @adrien2p in #13533
Full Changelog: v2.10.2...v2.10.3
v2.10.2
Highlights
Indexing of core entities
Medusa Index was built to improve the developer experience of filtering data across modules while improving performance, especially for large data sets.
With this release, all entities in the core Medusa modules are now ingestible into Medusa Index. This unlocks cross-module filtering for all core and custom entities. The ingestion happens automatically, provided a link is defined between the entities, as described in our documentation.
For example, filtering Products by Sales Channels used to require the following steps:
// 🔴 BEFORE
const query = container.resolve("query")
// Sales Channels to filter by
const salesChannels = ["sc_1234"]
// Query the Sales Channel <> Product link table for matching links
const { data: links } = await query.graph({
entity: "product_sales_channel",
fields: ["product_id"],
filters: {
sales_channel_id: salesChannels
}
})
// Construct the products filter using the matched links
const productFilters = {
id: links.map(link => link.product_id)
}
// Finally query the products with the filters
const { data: products } = await query.graph({
entity: "product",
fields: ["id"],
filters: productFilters
})With Index, the same example from above can be done with a single query:
// 🟢 NOW
const query = container.resolve("query")
// Sales Channels to filter by
const salesChannels = ["sc_1234"]
// Query the products with the sales channel filter
const { data: products } = await query.index({
entity: "product",
fields: ["id"],
filters: { sales_channels: { id: salesChannels } },
})Note that in the second code snippet, we use query.index instead of query.graph to query Medusa Index.
For setup and usage details of Medusa Index, see our documentation.
Locking all cart operations
All cart workflows in Medusa's core are now locking the cart during execution to eliminate the risk of concurrent changes.
We would recommend that you introduce the same locking mechanism to your own custom cart workflows.
Here's how you would do it:
export const myCustomAddToCartWorkflow = createWorkflow("my-custom-add-to-cart-workflow",
(input) => {
// Acquire a lock on the cart ID as the first step in the workflow
acquireLockStep({
key: input.cart_id,
timeout: 2, // Attempt to acquire the lock for two seconds before timing out
ttl: 10, // Lock is only held for a maximum of ten seconds
})
// Run all regular cart operations
// Release the lock on the cart ID as the last step in the workflow
releaseLockStep({
key: cart.id,
})
return new WorkflowResponse({ ... })
}
)Features
- feat(promotion): Allow buyget promotion to apply multiple times on cart by @riqwan in #13305
- feat(admin): add view configuration client infrastructure by @srindom in #13186
- Feat/datatable core enhancements by @srindom in #13193
- feat(ui): add column visibility and drag-and-drop reordering support by @srindom in #13198
- feat(admin): add configurable order views by @srindom in #13211
- feat(dashboard,cart,types,utils): refine order details summary by @willbouch in #13313
- chore(orchestration): add support for autoRetry, maxAwaitingRetries, retryStep by @adrien2p in #13391
Bugs
- fix(dashboard): rules form operator change by @fPolic in #13324
- fix(core-flows): handle cacluated shipping options on draft orders gracefully by @fPolic in #13353
- fix(utils): big bumber should give numeric value of 0 for small numbers by @willbouch in #13394
- fix(dashboard, ui): ensure radix deps version by @fPolic in #13392
- fix(dashboard): promotion decimal value definition by @fPolic in #13371
- fix(dashboard): customer
has_acccountflag by @fPolic in #13414 - fix(dashboard): support more decimals for tx rates by @willbouch in #13407
- fix: Missing DB traces in instrumentation by @olivermrbl in #13429
- fix(index): index enum fields by @carlos-r-l-rodrigues in #13428
- fix(medusa): Use default logger in plugin:develop by @olivermrbl in #13375
- fix(medusa): stop loading entry points in exec command by @willbouch in #13438
- fix(dashboard): edit rules clear and reset by @fPolic in #13423
- fix(): Prevent ci to fail if lock file does not exists by @adrien2p in #13456
- fix(): missing events by @adrien2p in #13465
- fix(): product image missing index by @adrien2p in #13466
- fix(): temporary transform cached data by @adrien2p in #13467
- fix(): prepare list query for list by @adrien2p in #13476
- chore(): improve inventory module by @adrien2p in #13463
- fix(): update cart line item route fetching by @adrien2p in #13477
- fix(medusa,product): fix ordering product categories by @willbouch in #13487
Documentation
- docs-util: fix error in references pipeline by @shahednasser in #13343
- docs: generate references for 2.10.1 by @shahednasser in #13344
- docs-util: fix workflows not picked for some routes + generate OAS by @shahednasser in #13342
- docs: document scheduled jobs interval by @shahednasser in #13350
- docs: add troubleshooting guide for pnpm installations by @shahednasser in #13351
- docs: add lockin module provider to deployment guide by @shahednasser in #13361
- docs: document how prices are stored in Medusa by @shahednasser in #13362
- docs: add missing step in product builder guide by @shahednasser in #13370
- docs: added a section on figma mcp + workflows diagram fix by @shahednasser in #13367
- docs: general updates and fixes by @shahednasser in #13374
- docs: change digial products to digital products by @yoreljenkins in #13379
- docs: document feature flags by @shahednasser in #13388
- docs: add more examples for API route responses by @shahednasser in #13399
- docs: show the source code link in order models reference by @shahednasser in #13398
- docs: change text in Cloud homepage by @MedusaNick in #13401
- docs: fix scrollbar not clickable by @shahednasser in #13409
- docs: added a note about payload version by @shahednasser in #13410
- docs: general fixes and improvements by @shahednasser in #13417
- docs: add plan cancelation details by @shahednasser in #13416
- docs: fixes and improvements to price calculation guide by @shahednasser in #13419
- docs: update project creation steps by @shahednasser in #13436
- docs: add graphql dependency to payload guide by @shahednasser in #13440
- chore(): Upgrade mikro orm by @adrien2p in #13390
- docs: add product feed tutorial by @shahednasser in #13366
- docs: fix cancel order information in user guide by @shahednasser in #13447
- docs: fix relations missing from data model reference diagrams by @shahednasser in #13474
- docs: improvements to Cloud homepage by @shahednasser in #13479
- docs: fix saved payment method guide by @shahednasser in #13480
- docs: fix same page link not resolved correctly by @shahednasser in #13481
- docs: add cloud plans & pricing page by @shahednasser in #13420
- docs: ticket booking system guide by @shahednasser in #13471
Chores
- chore(docs): Update version in documentation (automated) by @github-actions[bot] in #13340
- chore(docs): Updat...