Highlights
Global Product Options
🚧 Breaking change
Product options in Medusa can now be global — defined once at the store level and reusable across any number of products. Previously, options such as "Size" or "Color" had to be recreated independently for each product. With this release, you define an option once, attach it to as many products as you need, and manage values from a single place. This unlocks consistent variant modeling across large catalogs and reduces duplication when building storefront filters or admin tooling.
Read more in the announcement post.
Provider-Agnostic Auth Verification
🚧 Breaking change
Auth verification (email, phone, etc.) has been reworked into a flexible, provider-based system. You can now declare exactly which verifications are required per actor type and auth provider via the new authVerificationsPerActor config — for example, require email verification for customers using emailpass, but skip it for those signing in with Google. Codes are issued and confirmed through pluggable code providers, with a built-in token provider out of the box.
This is a breaking change:
- The verification endpoints moved from
POST /auth/:actor_type/:auth_provider/verification/request(and/confirm) to flatPOST /auth/verification/requestandPOST /auth/verification/confirm. The request route is now authenticated and takesentity_id,entity_type, andcode_providerin the body instead of actor/provider in the URL. - The JS SDK's auth verification methods were updated to match — upgrade the SDK and adjust any custom verification calls.
- A database migration replaces the
auth_verification_tokentable with a newauth_verificationtable. Runnpx medusa db:migrateafter upgrading; any pending (unconfirmed) verifications are discarded.
Medusa ESLint Plugin
A new @medusajs/eslint-plugin package ships with this release, bringing first-party linting rules for Medusa projects. The plugin covers API routes, subscribers, scheduled jobs, admin customizations, and module patterns. Lint runs automatically via the Medusa CLI when the plugin is installed:
npx medusa lintRules are grouped into config presets (recommended, modules, etc.) so you can opt in to the level of strictness that fits your project.
#15719
#15697
#15700
#15714
#15715
#15717
Features
- feat: global product options by @willbouch in #13817
- feat(order,types): add line_item_metadata to order responses by @NicolasGorga in #15727
- feat(dashboard): allow already registered actor to accept admin invite by @NicolasGorga in #15791
- feat(file-s3): add acl option to disable ACL headers on uploads by @mrpackethead in #15764
- feat: Revamp auth verification setup by @sradevski in #15696
- feat(admin-shared,dashboard,draft-order,loyalty): LayoutComposer, injection zones for plugins by @leobenzol in #15478
- feat(admin): add internal note support to order edits by @Tusharkhadde in #15690
- feat(cli, eslint-plugin, medusa): add linting to medusa CLI by @shahednasser in #15719
- feat(eslint-plugin): add rules for API routes by @shahednasser in #15697
- feat(eslint-plugin): added admin customization rules by @shahednasser in #15700
- feat(eslint-plugin): added rules for subscribers by @shahednasser in #15714
- feat(eslint-plugin): added rules for scheduled jobs by @shahednasser in #15715
- feat(eslint-plugin): add remaining eslint rules by @shahednasser in #15717
- feat(eslint-plugin): add
modulesconfig preset and support ESLint 8.57+ by @shahednasser - feat: pass scheduledFor to job handler by @peterlgh7 in #15815
- feat: Add publish timestamp to event metadata by @peterlgh7 in #15814
Bugs
- fix: handle bodyparser errors by @peterlgh7 in #15749
- fix: Run linting by default if eslint plugin is installed by @sradevski in #15816
- fix(medusa): update variant mutation endpoints query config to its retrieve query config by @NicolasGorga in #15735
- fix(core-flows): include order shipping method names in tax context by @gaoflow in #15783
- fix(dashboard): don't call hooks after an early return in UserLink by @merkelis-p in #15751
- fix(dashboard): don't call useTranslation inside NavItem items.map() by @merkelis-p in #15750
- fix(caching): invalidate list caches on entity update events by @imharjot in #15747
- fix: log single error log line by @peterlgh7 in #15748
- fix(medusa): maintain ESLint config detection behavior by @shahednasser in #15776
- fix: Remove unused actor type in auth module by @sradevski in #15761
- fix(eslint-plugin): handle link edge cases by @shahednasser in #15774
- fix(eslint-plugin): fix and improve main config by @shahednasser in #15758
- fix(eslint-plugin): fixes to avoid false positives by @shahednasser in #15743
- fix(core-flows, loyalty-plugin, medusa): fix medusa lint errors by @shahednasser in #15732
- fix(framework,medusa): surface real error and terminate process on db commands by @NicolasGorga in #15726
- fix(loyalty-plugin): respect user locale in currency formatting by @adem-loghmari in #15725
- fix(dashboard): feature flag rbac sidebar entries by @NicolasGorga in #15733
- fix(dashboard): prevent URL param collision breaking pagination in price list add products modal by @Tusharkhadde in #15704
- fix(pricing): return override as original_amount when a sale is stacked on an override by @cainydev in #15541
- fix(framework): match build ignore list against path segments by @sapirbaruch in #15577
- fix(core-flows): scope calculated shipping provider items to the option's shipping profile by @langovoi in #15163
- fix(promotion): prevent negative taxable base when stacking promotions by @shafi-VM in #15532
- fix(utils,dashboard): add GMD (Gambian Dalasi) to default currency lists by @kzroo in #15266
- fix: Await onapplicationstart by @sradevski in #15786
Documentation
- docs: product options changes by @shahednasser in #14290
- docs: added documentation for eslint plugin by @shahednasser in #15730
- docs: fix instructions for eslint plugin by @shahednasser in #15775
- docs: add references for custom MFA providers by @shahednasser in #15580
- docs: fix rules listing by @shahednasser in #15780
- docs(api-reference): fix broken loyalty plugin and storefront customers links by @sawirricardo in #15760
- docs(docs): correct Quote Management guide 404 links by @Kevin-jain in #15713
Chores
- chore(order): add line_item_metadata to OrderLineItem type by @NicolasGorga in #15734
- chore: add medusa eslint plugin to monorepo by @shahednasser in #15729
- chore: use the workspace version of the linter by @shahednasser in #15768
- chore(medusa): remove emojis from migration script by @shahednasser in #15740
- chore(draft-order, dashboard, loyalty-plugin): align react-router-dom version by @shahednasser in #15691
New Contributors
- @peterlgh7 made their first contribution in #15815
- @mrpackethead made their first contribution in #15764
- @merkelis-p made their first contribution in #15751
- @imharjot made their first contribution in #15747
- @gaoflow made their first contribution in #15783
- @leobenzol made their first contribution in #15478
- @Tusharkhadde made their first contribution in #15690
- @cainydev made their first contribution in #15541
- @sapirbaruch made their first contribution in #15577
- @langovoi made their first contribution in #15163
- @shafi-VM made their first contribution in #15532
- @kzroo made their first contribution in #15266
- @adem-loghmari made their first contribution in #15725
- @sawirricardo made their first contribution in #15760
- @Kevin-jain made their first contribution in #15713
Full Changelog: v2.16.0...v2.17.0