# medusa v2.20.0 — v2.20.0: Security Fixes, Performance Improvements, Calculated Shipping Options in Draft Orders - Product: medusa (https://whatsnew.fyi/product/medusa) - Vendor: medusa - Date: 2026-09-02 - Version: v2.20.0 - Original notes: https://github.com/medusajs/medusa/releases/tag/v2.20.0 - Permalink: https://whatsnew.fyi/product/medusa/releases/v2.20.0 What's New is an index, not a publisher: every entry below links to the vendor's own release notes, which are the authoritative source. Entries are labelled where they are hand-curated sample data, pre-releases, or drawn from a secondary source such as a developer blog. Reuse: the summaries, labels and curation here are © What's New. Quote freely with attribution and a link back; wholesale republication of the corpus is not permitted — terms: https://whatsnew.fyi/terms. The vendors' own release notes remain their publishers'. --- - **security** — Payment providers are now validated against the cart's region to prevent customers from initiating payment sessions with providers not linked to their region - **security** — MFA challenge enforcement on protected routes prevents attackers with a valid password from regenerating recovery codes or modifying MFA factors without completing MFA - **added** — Store API routes now enforce a default relations limit of three levels to prevent performance degradation from deeply nested expansions - **added** — Product routes allow four levels of relation expansions, one level deeper than other Store API routes - **added** — Configure the relations limit globally via storeRelationsLimit in HTTP configuration or per-route via validateAndTransformQuery middleware - **changed** — Redis caching provider now stores entries under a 64-bit hash key with a simplified storage mechanism, invalidating existing cache entries on upgrade - **added** — Inventory items can now be tracked in fractional quantities with an associated unit of measure - **added** — Draft orders now support shipping options with calculated prices from third-party rate providers - **added** — New setCalculatedShippingPricingContext hook allows injecting additional data into the pricing context for fulfillment provider rate calculations - **removed** — In-memory local search provider @medusajs/search-local has been removed - **changed** — searchMany method has been moved to the search provider interface requiring custom search providers to implement it - **changed** — Search indexes are no longer created at application startup and must be created by running db:migrate ##### Highlights Medusa MCP users can update their project using the following prompt: ```bash Update my Medusa project to v2.20.0 ``` ###### Payment providers are now validated against the cart's region Security fix: creating a payment session no longer trusts the payment provider ID passed in the request. The `createPaymentSessionsWorkflow` and the cart payment validation step now verify that the chosen provider is actually enabled in the cart's (or payment collection's) region, and reject the request otherwise. Previously a store customer could initiate a payment session with any payment provider installed in the application, even one that was not linked to their region. No action is required, but if your storefront relied on passing an arbitrary provider ID, make sure the provider is linked to the region the cart belongs to. --- ###### MFA Challenge Enforcement on MFA Routes Security fix: An attacker who already had a user's valid password could use that token to regenerate the recovery codes through `POST /auth/mfa/recovery-codes` and use one of them to complete the challenge, or enroll and delete MFA factors. This releases fixes this issue by tracking whether a user has completed MFA before allowing them to access the recovery codes route. --- ###### Relations Limit on Store API Routes 🚧 Breaking change > This only affects Store API requests that expand deeply nested relations through `fields`. Admin routes are unaffected. Store API routes now reject requests that expand more than three levels of relations in a single query by default, since deeply nested expansions can cause bad performance. A request such as `fields=*products.variants.options.values` now returns a `400` error listing the offending fields. The product routes are the only core Store routes that raise the limit above the default, allowing four levels of relations: - `GET /store/products` - `GET /store/products/:id` To change the limit for every Store route, set `storeRelationsLimit` in your HTTP configuration: ```ts title="medusa-config.ts" module.exports = defineConfig({ projectConfig: { http: { storeRelationsLimit: 4, }, }, }) ``` To change it for a specific route, set `storeRelationsLimit` in the query configuration passed to `validateAndTransformQuery` in your middlewares. It takes precedence over the application-wide configuration: ```ts title="src/api/middlewares.ts" import { defineMiddlewares, validateAndTransformQuery } from "@medusajs/framework/http" export default defineMiddlewares({ routes: [ { matcher: "/store/custom", method: "GET", middlewares: [ validateAndTransformQuery(GetCustomSchema, { defaults: ["id", "*items"], storeRelationsLimit: 5, isList: true, }), ], }, ], }) ``` --- ###### Redis Caching Storage Format > This only affects projects using the `@medusajs/caching-redis` provider. The Redis caching provider now stores entries under a 64-bit hash key and uses a simplified storage mechanism. Existing cache entries written by earlier versions are not readable in the new format and are effectively invalidated on upgrade, so expect a cold cache after deploying. No configuration change is required. --- ###### Fractional Inventory Quantities and Units of Measure Inventory items can now be tracked in fractional quantities with an associated un _[Truncated at 4000 characters — full notes: https://github.com/medusajs/medusa/releases/tag/v2.20.0]_