Building a Wishlist Feature in Medusa.js: A Step-by-Step Implementation
Wishlists sound like a simple feature until you actually try to add one to a Medusa.js storefront. Since a Medusa.js wishlist feature does not ship as part of the core commerce modules, most teams end up building it slightly differently depending on whether guests need wishlists too, whether items should sync across devices, or whether the list should double as a shareable page. Medusa's own wishlist plugin guide is a good reference point, and this walkthrough builds on that foundation with a practical, step by step approach covering the data model, the storefront API routes, and the front end pieces that tie everything together.
Why a Wishlist Still Earns Its Place in a Medusa Storefront
A wishlist gives shoppers a reason to come back without abandoning a cart just to hold their place. It also gives a store useful signal, since products saved but never bought point to pricing friction or timing issues rather than a lack of interest. For a Medusa.js build, adding this feature properly means deciding early how wishlist data is stored and whether it needs to survive a browser refresh, a device switch, or a customer logging in later from their phone.
Planning the Wishlist Data Model Before Writing Any Code
There are two common ways to store wishlist data in Medusa. The quicker route uses the existing customer metadata field to hold an array of product variant IDs, which works fine for smaller catalogs and simpler stores. The more scalable route is a dedicated wishlist module with its own data model, migrations, and relations to customers and product variants, which pays off once you need sharing, analytics, or multiple wishlists per customer.
Need Custom Medusa Features?
Lets TalkSetting Up the Wishlist Module
If you go the dedicated module route, scaffold it the same way you would any other Medusa module, with its own data model storing the customer ID and product variant ID as a pair, plus a timestamp for sorting. Medusa's modular architecture, the same one described in Askan's breakdown of the Medusa.js headless backend, makes this straightforward since a new module does not need to touch the core commerce logic at all. Run the migration, confirm the table exists, and the module is ready to be wired into API routes.
Building the Storefront API Routes
With the data model in place, three routes cover most wishlist needs. A POST route under a path such as /store/customers/:id/wishlist adds an item, a DELETE route removes one, and a GET route returns the full list with basic product details expanded for display. Keep the response shape close to what Medusa already returns for cart line items, since it makes reusing existing product card components on the frontend much easier.
Wiring Up the Add to Wishlist Button
On the frontend, a heart icon on the product card is the standard pattern, toggling between saved and unsaved states. Update the UI optimistically as soon as the customer clicks, then reconcile with the actual API response in the background. If the customer is not logged in, either prompt them to sign in or, better for conversion, let the click go through anyway and store it temporarily so nothing is lost.
Talk to Medusa Developers
Lets TalkHandling Guest Wishlists Without Losing Data
For guests, store wishlist items in the browser using a simple in-memory or session-based store on the frontend rather than relying on any server record tied to an account. Once the customer logs in or creates an account, merge that temporary list into their server-side wishlist in a single call. This avoids the common frustration of a shopper saving five items, signing in, and finding an empty wishlist.
Displaying and Managing the Wishlist Page
The wishlist page itself should handle three states cleanly: a populated list, an empty state with a nudge back to browsing, and a loading state while data fetches. A move to cart button next to each item removes friction between saving something and actually buying it. For teams weighing a fully custom Medusa build against a ready-made storefront subscription, comparing a hosted platform's pricing page, such as Zyfoo's pricing, is a useful way to put a number on the engineering time a custom feature like this actually takes.
Testing the Feature Before It Reaches Customers
Run through the table above on both desktop and mobile viewports before shipping, since wishlist icons are easy to overlook in a mobile layout review. Once the core flow holds up under manual testing, a wishlist feature built this way tends to need very little maintenance, since it sits on top of Medusa's existing product and customer data rather than duplicating it.
