Skip to content

medusa

v2.22.7
medusajs/medusa

The world's most flexible commerce platform for agents and developers

Version of medusajs/medusa you run

CompareView on GitHub

Breaking changes

What to check before upgrading, taken from the notes of the last 30 releases.

  • v2.20.0Sep 2, 2026

    Breaking Changes

    • Relations limit on store routes — Store API routes now enforce a default relations limit to cap query depth and improve performance. Requests that relied on unbounded relation expansion may see fewer nested associations returned. Run db:migrate after upgrading. (#16688)
    • In-memory local search provider removed — @medusajs/search-local (the Orama-backed in-memory provider shipped in v2.19) has been removed. Projects must switch to @medusajs/search-postgres, the Medusa Cloud provider, or a custom provider. Search indexes are no longer created at application startup; run db:migrate to create them. (#16545)
    • searchMany moved to the provider interface — The searchMany method has been pushed down to the search provider interface so each provider can optimize batch queries internally. Custom search providers must implement searchMany. (#16643)
    • MFA routes now require a completed challenge — MFA-protected routes now validate that the MFA challenge has actually been completed before granting access, hardening the authentication flow. (#16610)

    ---

  • v2.14.0Apr 23, 2026

    Breaking changes to fix

    Error customization

    • Replace invalid_type_error and required_error options with the unified error param
    • BEFORE: z.string({ invalid_type_error: "Not a string", required_error: "Required" })
    • AFTER: z.string({ error: (issue) => issue.input === undefined ? "Required" : "Not a string" })
    • Rename errorMap option to error wherever used

    ZodError

    • Replace .format() and .flatten() calls with z.treeifyError(err)
    • Remove .formErrors usage (identical to deprecated .flatten())
    • Replace .addIssue() / .addIssues() calls with direct pushes to err.issues

    z.string() format validators

    • Replace z.string().email() with z.email() (top-level)
    • Replace z.string().url() with z.url() (top-level)
    • Replace z.string().uuid() with z.uuid() — note: now RFC 9562 strict; use z.guid() if lenient matching is needed
    • Replace z.string().ip() with z.ipv4() or z.ipv6() depending on intent
    • Replace z.string().cidr() with z.cidrv4() or z.cidrv6() depending on intent
    • Replace z.string().emoji() with z.emoji() (top-level)
    • Replace z.string().base64url() — note it no longer accepts padding

    z.number()

    • Remove any inputs passing Infinity or -Infinity — they are now rejected
    • Review .safe() usage — it now behaves like .int() and rejects floats

    z.object()

    • Replace .strict() with z.strictObject({ ... })
    • Replace .passthrough() with z.looseObject({ ... })

Release history

All releases on GitHub
BadgeLatest version of medusajs/medusa[![version](/badge/medusajs/medusa)](/p/medusajs/medusa)

v2.22.7: Translation Module Stable, Cross Module Joins, Promotion Events

Highlights

Translation Module Stable

The Translation Module is out of beta is now installed in all Medusa projects by default. You can use translation features to translate content for products, categories, custom data models, and more.

Learn more in the Translation Module documentation.

---

Cross-Module Joins Replace the Index Module

Medusa now resolves cross-module queries using direct database joins rather than the Index Module, including in the /store/products API route. The Index Module is deprecated and will be removed in a future release.

If you have explicitly registered the Index Module in your project, you can remove it from your modules configuration. Cross-module queries via query.graph() and API filters that span module boundaries continue to work without any changes.

// In medusa-config.ts, remove the Index Module registration if present:
// { resolve: "@medusajs/index" }

Learn more about cross-module joins with Query in the documentation.

---

Security Fix for Index Module

This release also comes with a security fix for users that have enabled the Index Module feature flag in their store. It ensures proper handling of ? characters in query parameters passed to the /store/products and /store/product-variants.

If you can't update to this version, we urge you to download and apply the patch of your Medusa version:

---

Promotion and Campaign Events

Medusa now emits events when promotions, promotion rules, and campaigns are created, updated, or deleted. Subscribers can react to these events to trigger automation workflows in response to discount and promotion changes.

#17136

---

Medusa Cloud Plugin

A new Medusa Cloud plugin integrates the admin dashboard with Medusa Cloud, surfacing in-app announcements about platform updates and new features directly in the admin UI. The plugin is included automatically for projects deployed on Medusa Cloud.

#17518

Features

  • feat(cloud): add Medusa Cloud plugin with in-app announcements by @shahednasser in #17518
  • feat: Redesign permissions UI by @olivermrbl in #17778
  • feat(audit): add the Audit Module with Postgres and Medusa Cloud providers by @sradevski in #17787
  • feat(framework,medusa,types,js-sdk,audit): record API requests as audit logs by @sradevski in #17795
  • feat: improve handling of missing account holders for medusa payments by @sradevski in #17389
  • feat(core-flows,utils): emit events for promotion, promotion rule, and campaign changes by @shahednasser in #17136
  • feat(medusa,types,framework): use cross-module joins instead of the index module by @shahednasser in #17751
  • feat(framework,types): allow additional cors option in project config by @NicolasGorga in #17576
  • feat(core-flows): include metadata in the order passed to createOrderWorkflow's orderCreated hook by @shahednasser in #17058

Bugs

  • fix(utils): resolve plugins installed as dependencies of @medusajs/medusa by @shahednasser in #17822
  • fix(admin-bundler): resolve admin extensions of plugins that aren't direct project dependencies by @shahednasser in #17820
  • fix(types): allow the q free-text filter in query.graph filters by @shahednasser in #17775
  • fix(create-medusa-app): support installing projects with Yarn v1 by @shahednasser in #17794
  • fix(index,promotion,product): handle ? characters in filter and context values by @shahednasser in #17773
  • fix(core-flows): assign the super admin role to created users when no super admin exists, so users provisioned through SSO on a new RBAC deployment aren't locked out by @NicolasGorga in #17782
  • fix(core-flows): only guard the last super admin when a removal takes the super admin role from a user by @NicolasGorga in #17767
  • fix(dashboard): show an error toast when updating product attributes fails by @medusa-os-bot in #17772
  • fix(promotion): check spend campaign budgets against all adjustments in a cart and skip promotions that don't fully fit by @medusa-os-bot in #17599
  • fix(core-flows): re-price cart shipping methods after promotions are recomputed by @shahednasser in #17070
  • fix(dashboard): disable product media Save while media is uploading by @medusa-os-bot in #17769
  • fix(utils,medusa): invalidate cached localized reads and the admin translation list when a translation is created, updated or deleted by @NicolasGorga in #17746
  • fix(framework,types): set security headers on HTTP responses by @shahednasser in #17763
  • fix(ui,dashboard): stop DatePicker from calling onChange when its value prop changes and setSearchParams being called twice by @NicolasGorga in #17759
  • fix(core-flows): don't record order refund transactions for refunds the payment provider rejected in refundPaymentsWorkflow by @NicolasGorga in #17748
  • fix(payment): recompute refunded amount when a refund fails at the provider by @shahednasser in #17489
  • fix(utils): accept variant thumbnail and image columns in product import by @medusa-os-bot in #17488
  • fix(event-bus-redis,workflow-engine-redis): catch failed Redis connects in loaders by @medusa-os-bot in #17553
  • fix(utils,create-medusa-app): escape database names in database creation and existence queries by @shahednasser in #17521
  • fix(promotion): don't apply buyget discounts to non-discountable items by @medusa-os-bot in #17443
  • fix(product): don't run parallel queries inside category and variant creation by @medusa-os-bot in #17453

Full release notesCompare with previous