Highlights
This release comes with new features, bug fixes, and dependency updates for better security.
Medusa MCP users can update their project using the following prompt:
Update my Medusa project to v2.18.0Balanced Query Load Strategy by Default
🚧 Breaking change
The default database load strategy has changed from SELECT_IN to BALANCED, matching MikroORM v7's intended default. MikroORM picks between a joined and a select-in approach per relation, which improves query performance in most cases. Because it changes how relations are loaded, review query-heavy paths and any snapshot or query-count assertions in your tests after upgrading.
Return Value of Generated Internal Service's delete Method Changed
🚧 Breaking change
This affects usages of generated internal services. They do not impact methods generated by
MedusaServicesuch asdeletePosts.
The return value of the delete method of a generated internal service has been changed to cater for composite primary keys:
// before
delete(idOrSelector: string, sharedContext?: Context): Promise<string[]>
delete(idOrSelector: string[], sharedContext?: Context): Promise<string[]>
delete(idOrSelector: object, sharedContext?: Context): Promise<string[]>
delete(idOrSelector: object[], sharedContext?: Context): Promise<string[]>
delete(
idOrSelector: {
selector: FilterQuery<any> | BaseFilterable<FilterQuery<any>>
},
sharedContext?: Context
): Promise<string[]>
// after
delete(
idOrSelector: string,
sharedContext?: Context
): Promise<string[] | Record<string, any>[]>
delete(
idOrSelector: string[],
sharedContext?: Context
): Promise<string[] | Record<string, any>[]>
delete(
idOrSelector: object,
sharedContext?: Context
): Promise<string[] | Record<string, any>[]>
delete(
idOrSelector: object[],
sharedContext?: Context
): Promise<string[] | Record<string, any>[]>
delete(
idOrSelector: {
selector: FilterQuery<any> | BaseFilterable<FilterQuery<any>>
},
sharedContext?: Context
): Promise<string[] | Record<string, any>[]>The method now either returns an array of deleted IDs if the primary key is an id field, or an array of objects, each object's keys are the composite primary key's name, and value is the primary key's value. For example, [{ foo: "foo-1", var: "bar-1" }].
If you use generated internal services in your module, make sure to update their usages to handle the new return value. For example:
// before
const deletedIds = await postService.delete(idsOrObject) // type was string
// after
// type could be an array of string IDs or objects.
const deletedData = await postService.delete(idsOrObject)
const isStringIds = deletedData.some((data) => typeof data === "string")Improved Configurable Data Tables in the Admin Dashboard
The view configurations feature in the Medusa Admin dashboard. has been improved Users can resize columns, control column visibility and ordering, and save view configurations, with dynamic filter and sort resolution, custom cell renderer registration, and a UI for managing property labels.
Learn more in this documentation
view-config-2.mp4
Transfer an Order to a Guest Customer
Orders can now be transferred to a guest customer from the admin dashboard without going through a full order transfer flow. This makes it possible to reassign an order to a guest account when it was placed under the wrong customer or needs to be detached from a registered account. The original customer transfer flow remains for transferring orders to registered customers.
New Inventory Events
The inventory workflows now emit domain events, so you can subscribe to inventory changes and run side effects such as syncing stock to external systems or notifying on low levels.
Short-Lived Database Credentials for AWS RDS IAM
createPgConnection now forwards dynamicPassword and expirationChecker from databaseDriverOptions to the underlying connection. When running on AWS RDS with IAM authentication (or any setup with short-lived credentials such as Azure AD tokens, GCP IAM, or Vault dynamic secrets), tokens expire after roughly 15 minutes. Previously these fields were silently dropped, causing authentication failures once the pool opened new connections. You can now mint a fresh token per connection:
// medusa-config.ts
import { Signer } from "@aws-sdk/rds-signer"
import { defineConfig } from "@medusajs/framework/utils"
const signer = new Signer({ hostname, port, username })
export default defineConfig({
projectConfig: {
databaseDriverOptions: {
dynamicPassword: () => signer.getAuthToken(),
expirationChecker: () => true, // always fetch a fresh token
},
},
})Stripe Payment Method Configurations
The @medusajs/payment-stripe provider now supports Stripe Payment Method Configurations (PMC) through a new paymentMethodConfiguration option. The value is forwarded as payment_method_configuration when creating a PaymentIntent, and can be overridden per request via extra.payment_method_configuration. This lets merchants manage which payment methods appear to customers from the Stripe Dashboard, without code changes or redeploys.
// medusa-config.ts
{
resolve: "@medusajs/payment-stripe",
id: "stripe",
options: {
apiKey: process.env.STRIPE_API_KEY,
paymentMethodConfiguration: "pmc_xxx",
},
}Security: Dependency Updates
This release resolves all Dependabot security alerts by bumping vulnerable dependencies. Notable updates include:
multer(2.0.2 to 2.2.0)qs(6.14.0 to 6.15.2)@opentelemetry/sdk-node(0.218.0 to 0.220.0)@opentelemetry/resourcesand@opentelemetry/sdk-trace-node(2.0.0 to 2.7.0)
If you've explicitely installed any of these packages, make sure to update to the same new version to avoid unexpected issues. For the full list of updated dependencies check out PRs #16083, #16089, #16082, and 16158
Features
- feat: Implement support for cross-module filtering at the DAL by @sradevski in #15918
- feat: Pass crossjoinable info to joiner by @sradevski in #15951
- feat(admin-vite-plugin,dashboard): add config.label to document title resolution seo fallback by @NicolasGorga in #15984
- feat(dashboard,medusa,types): filter notifications in admin dashboard for logged in user by @NicolasGorga in #15923
- feat(core-flows): automatically refresh taxes upon state change by @NicolasGorga in #15924
- feat(dashboard): resizable datagrid columns by @NicolasGorga in #15925
- feat(core-flows, utils): emit inventory-related events by @shahednasser in #15991
- feat(eslint-plugin): add a rule for wildcard + specific field selections in query by @shahednasser in #16037
- feat(core-flows,medusa,types,js-sdk,dashboard): transfer order to guest customer by @NicolasGorga in #15926
- feat(dashboard,admin-vite-plugin,admin-shared,ui,settings,js-sdk,types): view configuration UI enhancements — dynamic filter/sort resolution, custom cell renderer registration, property labels management UI by @NicolasGorga in #14661
- feat(framework): add helpful hint for admin users using incorrect api key header by @shahednasser in #16062
- feat: Implement support for cross-module joins by @sradevski in #15979
- feat: Use a balanced load strategy which will be the default in mikro… by @sradevski in #16137
- feat(payment-stripe): add paymentMethodConfiguration option by @vssavosko in #15191
- feat(utils): add Iranian Toman (IRT) currency by @KMLnk in #15948
- feat(dashboard): pass order ID as a query parameter in storefront payment link by @shahednasser in #16127
- feat: Implement second stage of cross-module joins by @sradevski in #16131
- feat(dashboard,settings,ui,types): implement configurable data tables end to end in admin dashboard by @NicolasGorga in #16025
- feat(create-medusa-app): detect nub package manager by @colinhacks in #15898
- feat: Extract query engine to package by @sradevski in #15900
- feat(core-flows,types,utils,medusa): support global product options in imports by @shahednasser in #15614
- feat(docs): JSON doc-model TypeDoc theme + generator by @shahednasser in #16042
- feat(docs): serve the JSON doc-model + remove MDX by @shahednasser in #16044
- feat: Cleanup query package structure by @sradevski in #15934
- feat: Refactor joiner by @sradevski in #15972
- feat(dashboard): update Brazilian Portuguese (ptBR) translations by @diwberg in #16015
- feat(utils): support dynamic password function in createPgConnection for RDS IAM auth by @mrpackethead in #15686
- feat(types,core-flows,order): add metadata to tax lines returned by providers by @nam-stx in #15840
Bugs
- fix(dashboard): call useStateAwareTo unconditionally in RouteFocusModal by @merkelis-p in #15752
- fix(dashboard): fixes to sidebar styling for layout configuration by @shahednasser in #15985
- fix(core-flows): correctly clear a region payment providers by @NicolasGorga in #15986
- fix(eslint-plugin): remove use-query-context-utility rule by @adem-loghmari in #15850
- fix(file-s3,file-local): decode upload content by MIME type to stop binary file corruption by @BIGSUS24 in #15811
- fix(utils): fix delete operation when primary key is not
idby @shahednasser in #15989 - fix(utils): apply select in strategy for single entity fetches by @shahednasser in #15990
- fix(utils): prevent nested mikroOrm serialization from mutating parent keys by @dosacha in #15806
- fix(payment, medusa): reject refunds and captures of negative or 0 amount by @shahednasser in #16036
- fix(medusa): use email compatible validation with zod by @shahednasser in #16055
- fix(utils): stop double-counting tax on discounts in refundable_total for non-tax-inclusive items by @shafi-VM in #15886
- fix(framework): fix middlewares regex matcher by @shahednasser in #16066
- fix(test-utils): replace unmaintained pg-god with @medusajs/framework/pg by @shafi-VM in #15887
- fix(modules-sdk, framework): fail early when can't connect to the database by @shahednasser in #16100
- fix(framework): register HTTP compression middleware by @AkashRanjan18 in #15957
- fix(js-sdk): handle blocked browser storage by @Arunsiva003 in #15941
- fix(core-flows): only complete cart from payment webhook on definitive actions by @rodriguescarson in #15930
- fix(utils): assign per-adjustment subtotal/total instead of cumulative sum by @Venkat-jaswanth in #16013
- fix(dashboard): don't mark promotions with per-attribute campaign budgets as expired by @MahinAnowar in #16018
- fix(dashboard): sorting countries by name or code no longer throws error by @andrewaltos in #16020
- fix: add missing keys to Persian (fa) translation file by @rasa7x in #16071
- fix(utils): add BigNumber.toString() to avoid '[object Object]' coercion by @Venkat-jaswanth in #16014
- fix(dashboard): handle empty price rules on price list price updates by @MahinAnowar in #15942
- fix(caching-redis): read ioredis options from redisOptions for consistency with other Redis modules by @mvanhorn in #16101
- fix(core-flows): filter reservations by line item in createOrderFulfillmentWorkflow by @andrewgreenh in #16136
- fix(framework, utils): defensive handling of dotted path segments by @shahednasser in #16123
- fix(framework, types, medusa): add disallowed query config to restrict retrieved fields by @shahednasser in #16125
- fix(order): version-scope shipping method adjustments in select-in (list) path by @nbwar in #15920
- fix(create-medusa-app): fix ajv error in npm installation by @shahednasser in #16124
- fix(product): emit PRODUCT_CATEGORY_DELETED event on soft delete by @adem-loghmari in #16126
- fix(js-sdk): avoid Vite import-analysis conflict with Product.import method by @ashif323 in #15899
- fix(dashboard): allow same conditional shipping price amount for different conditions by @Ligament in #16130
- fix(dashboard): fix edit reservartion form not showing anything by @shahednasser in #16132
- fix(payment,promotion): serialize concurrent money guards to prevent over-capture, over-refund and budget overspend by @Meliceanu in #16097
- fix(modules-sdk): validate link uniqueness on batch links being created by @shahednasser in #16144
- fix(core-flows): refresh cart tax lines on any tax-relevant shipping address change by @shahednasser in #16035
- fix(dashboard): prevent product option badges from overlapping with long option values by @khchen-doit in #15902
- fix(loyalty): honor configured admin auth type in admin SDK by @shahednasser in #16164
- fix: Support cross module filtering on belongs to foreign key by @sradevski in #16167
- fix(framework): load workflows from index.[js,ts] files in worker mode by @MahinAnowar in #15702
- fix(utils): apply onUpdate hooks before nativeUpdateMany by @sawirricardo in #15694
- fix(eslint-plugin): normalize Windows paths in module relationship rule by @gaoflow in #15784
- fix(core-flows): pass customer groups to pricing context in createCartWorkflow by @Kelpy2004 in #15746
- fix(admin,utils): add AOA currency and guard region editor against unknown currencies by @BIGSUS24 in #15797
- fix(core-flows): translate line items when creating an order with a l… by @shafi-VM in #15804
- fix(medusa): return 400 instead of 500 for invalid promotion rule attribute with a value filter by @shafi-VM in #15819
- fix(rbac): add missing migration for RbacRoleInheritance model by @pevey in #15833
- fix(medusa,utils): defineConfig typed modules by @leobenzol in #15834
- fix(dashboard): use total count instead of page length for product type products table pagination by @Tusharkhadde in #15950
- fix: skip self-join for readonly links in cross-module filters by @peterlgh7 in #15968
- fix(core-flows): preserve data field in prepareTaxLinesData during cart completion by @nam-stx in #15969
- fix(core-flows): only emit RETURN_RECEIVED when receive_now is true by @d3v07 in #15856
- fix: resolve Dependabot security update failure for @opentelemetry/core by @shahednasser with @Copilot in #16082
Documentation
- docs: add TSDocs for "update variant mutation endpoints query config to its retrie" by @shahednasser in #15812
- docs: add TSDocs for "use layout composer in Topbar, Sidebar and settings Sidebar " by @shahednasser in #15894
- docs: add TSDocs for "add acl option to disable ACL headers on uploads (#15764)" by @shahednasser in #15787
- docs: add TSDocs for "make custom_display_id searchable (#15622)" by @shahednasser in #15895
- docs: add TSDocs for "add metadata to tax lines returned by providers (#15840)" by @shahednasser in #15944
- docs: fix documentation issues in triage inbox by @shahednasser in #15793
- docs: fix documentation issues in triage inbox by @shahednasser in #15794
- docs: fix documentation issues in triage inbox by @shahednasser in #15817
- docs: fix documentation issues in triage inbox by @shahednasser in #15860
- docs: fix documentation issues in triage inbox by @shahednasser in #15866
- docs: fix documentation issues in triage inbox by @shahednasser in #15889
- docs: fix documentation issues in triage inbox by @shahednasser in #15903
- docs: fix documentation issues in triage inbox by @shahednasser in #15931
- docs: fix documentation issues in triage inbox by @shahednasser in #15946
- docs: fix documentation issues in triage inbox by @shahednasser in #15958
- docs: fix pricing page in cloud docs by @shahednasser in #15975
- docs: remove bloom by @shahednasser in #15970
- docs: add TSDocs for "support global product options in imports (#15614)" by @shahednasser in #15982
- docs: add documentation for layout configuration user guide + ui route title by @shahednasser in #15988
- docs: add docs for changing infrastructure specs in cloud by @shahednasser in #15993
- docs: use caching + binding by @shahednasser in #16016
- docs: fix documentation issues in triage inbox by @shahednasser in #16007
- docs: add code contribution guide by @archievi in #15638
- docs: improve instructions for MCP server by @shahednasser in #15998
- docs: fix documentation issues in triage inbox by @shahednasser in #16031
- docs: add docs for big numbers by @shahednasser in #16028
- docs: add info on when taxes are recalculated for carts and orders by @shahednasser in #16032
- docs: updates related to buyget promotions with clarifications by @shahednasser in #16039
- docs: clarifications for pricing docs by @shahednasser in #16046
- docs: fix typos across learn guides by @adem-loghmari in #15795
- docs: fix deploy command by @shahednasser in #16049
- docs: add TSDocs for "transfer order to guest customer (#15926)" by @shahednasser in #16048
- docs: fix markdown content returning 404 by @shahednasser in #16052
- docs: improve docs for pricing and shipping option price types by @shahednasser in #16056
- docs: improvements in promotions related to application methods and values by @shahednasser in #16060
- docs: fix type of api token security schema by @shahednasser in #16063
- docs: fix documentation issues in triage inbox by @shahednasser in #16061
- docs: mcloud CLI updates for 0.1.10 by @shahednasser in #16067
- docs: add TSDocs for "Implement support for cross-module joins (#15979)" by @shahednasser in #16069
- docs: add reservations lifecycle doc by @shahednasser in #16074
- docs: add docs for linking a user to multiple providers by @shahednasser in #16076
- docs: fix documentation issues in triage inbox by @shahednasser in #16073
- docs: clarifications for default fields in data models by @shahednasser in #16080
- docs: added changelog automation for mcloud CLI by @shahednasser in #16072
- docs: improvements to JS SDK and UI docs by @shahednasser in #16086
- docs: Fix Docker installation link text in page.mdx by @shahednasser in #16090
- docs: update terminology from 'Customer' to 'Actor' by @shahednasser in #16096
- docs: add markdown parser for ChildDocs component by @shahednasser in #16108
- docs: add documentation on product attributes by @shahednasser in #16134
- docs: add section on using JS SDK for downloading files by @shahednasser in #16140
- docs: fix documentation issues in triage inbox by @shahednasser in #16146
- docs: document suspension policy on cloud by @shahednasser in #16148
- docs: added section for codex in mcp server docs by @shahednasser in #16155
- docs: add TSDocs for "implement configurable data tables end to end in admin dashb" by @shahednasser in #16160
- docs: fix "occured" typo in workflows errors guide by @BIGSUS24 in #15796
- docs: clarify telemetry collection across CLI commands by @vansh17June in #16058
- tsdocs: improvements related to payments and cart completion by @shahednasser in #16077
Chores
- chore: Add tests to DAL cross-join to test readonly links by @sradevski in #15955
- chore: update node version in actions by @shahednasser in #15971
- chore(deps): refresh immutable transitive to resolve GHSA-wf6x-7x77-mvgw by @shahednasser in #16088
- chore(deps): refresh minimatch to patch ReDoS (GHSA-3ppc-4f35-3m26) by @shahednasser in #16094
- chore(docs): doc changes for next release (automated) by @shahednasser in #15777
- chore(docs): Updated UI Reference (automated) by @github-actions[bot] in #15908
- chore(docs): Generated DML JSON files (automated) by @github-actions[bot] in #15906
- chore(docs): Generated References (automated) by @github-actions[bot] in #15910
- chore(docs): Updated API Reference (automated) by @github-actions[bot] in #15909
- chore: update tsdocs for layout configurations by @shahednasser in #15983
- chore(docs): add generated JSON reference pages by @shahednasser in #16043
- chore(docs): cloud doc changes (automated) by @shahednasser in #16050
- chore: repo dependency updates by @shahednasser in #16106
- chore(docs): cloud doc changes (automated) by @shahednasser in #16107
- chore(docs): cloud doc changes (automated) by @shahednasser in #16149
- chore(docs): cloud doc changes (automated) by @shahednasser in #16152
- chore(docs): cloud doc changes (automated) by @shahednasser in #16154
- chore: set actions permission for draft release step by @NicolasGorga in #15905
- chore: pin node and npm versions in actions by @shahednasser in #15978
- chore(docs): Update version in documentation (automated) by @github-actions[bot] in #15907
- chore: changes to doc jobs by @shahednasser in #15992
- chore: clarify payment validation details in completeCartWorkflow's tsdocs by @shahednasser in #16038
- chore: improvements to cart and pricing tsdocs by @shahednasser in #16047
- chore: improve tsdocs of shipping option price type and related methods by @shahednasser in #16057
- chore: improvements to tsdocs for fulfillments and reservations by @shahednasser in #16075
- chore: configure and manage dependabot alerts by @shahednasser in #16081
- chore: add PR review handling for dependabot and dependency update PRs by @shahednasser in #16087
- chore(file-s3,framework): raise @aws-sdk dependency for issue flagged by dependabot alert by @shahednasser in #16089
- chore: remove medusa-dev-cli package by @shahednasser in #16095
- chore: refresh lock file by @shahednasser in #16092
- chore: add action to trigger preview bump in starter by @shahednasser in #16102
- chore: fix issue triager comment truncation by @shahednasser in #16103
- chore: update PR reviewer to flag similar previous PRs by @shahednasser in #16104
- chore: Surface redis cache connection issues by @olivermrbl in #16091
- chore: increase max turns on issue triager by @shahednasser in #16111
- chore: improvements to PR automations by @shahednasser in #16112
- perf(pricing): pre-filter matching price lists in calculatePrices (x10 perf in B2B scenario) by @docloulou in #15913
- chore: create advisories as tickets by @shahednasser in #16138
- chore: improvements to issues and PR triagers by @shahednasser in #16143
- chore(admin-bundler): block Vite's launch-editor dev-server endpoint by @shahednasser in #16105
- chore: fix triage and review actions + dependency updates by @shahednasser in #16147
- chore(deps): bump @opentelemetry/sdk-node to ^0.220.0 by @shahednasser in #16158
- chore: automate transitive dependabot alerts by @shahednasser in #16161
- chore(deps): bump the security-updates group across 1 directory with 15 updates by @dependabot[bot] in #16083
Other Changes
- Fix/more improvements query package by @sradevski in #15915
- Fixes #15300 :- exit with code 1 when db commands fail to initialize container by @Ultron03 in #15302
- Fix changeset by @NicolasGorga in #15964
- support cross-module filters in order module by @peterlgh7 in #16114
- force inner joins to avoid entities being hidden by deleted related e… by @peterlgh7 in #16141
New Contributors
- @MahinAnowar made their first contribution in #15702
- @BIGSUS24 made their first contribution in #15796
- @Kelpy2004 made their first contribution in #15746
- @nam-stx made their first contribution in #15840
- @d3v07 made their first contribution in #15856
- @dosacha made their first contribution in #15806
- @vansh17June made their first contribution in #16058
- @AkashRanjan18 made their first contribution in #15957
- @Arunsiva003 made their first contribution in #15941
- @rodriguescarson made their first contribution in #15930
- @Venkat-jaswanth made their first contribution in #16013
- @andrewaltos made their first contribution in #16020
- @rasa7x made their first contribution in #16071
- @andrewgreenh made their first contribution in #16136
- @nbwar made their first contribution in #15920
- @diwberg made their first contribution in #16015
- @vssavosko made their first contribution in #15191
- @KMLnk made their first contribution in #15948
- @Meliceanu made their first contribution in #16097
- @colinhacks made their first contribution in #15898
- @khchen-doit made their first contribution in #15902
Full Changelog: v2.17.2...v2.18.0