TL;DR
I migrated Heartbeat Pharmacy from a planned Shopify Plus launch onto Medusa.js. The driving reason was not the developer experience or the dev tooling: it was the margin. Shopify Plus takes a percentage of every transaction on top of the platform fee. A growing pharmacy with thousands of low-margin SKUs cannot keep paying that, year after year, for software it does not own. Medusa.js gives you the same checkout, the same admin UI, the same fulfillment flow, on a stack the business owns outright.
Below is the actual breakdown of the decision and what the migration looked like in practice.
The Shopify Plus problem (it isn’t just the price)
Shopify Plus advertises itself as an enterprise-tier headless commerce platform. For most retailers in the US or UK it’s a reasonable choice. For a Greek pharmacy specifically, three issues compound:
- Per-transaction fees. Plus charges a flat platform fee plus a percentage on every order that does not go through Shopify Payments. In Greece, Shopify Payments is not available, which means every transaction is on a “third-party gateway” tier and gets the higher percentage. Compounded across thousands of orders, this is real margin lost to a vendor.
- No native Greek integrations. The Greek courier ecosystem (ACS, BoxNow, Courier Center, ELTA, Geniki) and the Greek bank payment gateways (Piraeus Bank, Alpha Bank) are not in the stock Shopify app store. The available third-party apps are paid, often unmaintained, and frequently break across Shopify version bumps.
- No regulatory pharma master-data. Greek pharmacy regulation requires a real connection to the regulatory master-data system over SOAP. Shopify will never ship a first-party integration for this; a custom Shopify app would need to be built and hosted separately anyway, defeating the “we don’t have to host anything” pitch.
The first issue is the one most businesses notice. The second and third are what kill the platform for verticals like pharmacy.
What Medusa.js gives you
Medusa.js is an open-source, TypeScript-first headless commerce backend. The architecture is:
- A Node.js + PostgreSQL backend you run yourself, with the cart, checkout, products, inventory, fulfillment, payments, and customer modules implemented as a clean tree of services.
- A Next.js storefront starter that talks to the backend over a typed SDK.
- A React-based admin UI for the day-to-day catalog + order operations.
The piece that matters is that you own the data. The Postgres database is yours. The catalog is yours. The customer list is yours. There is no per-transaction percentage going anywhere because there’s no platform sitting between you and the payment processor — the payment plugin talks directly to your bank’s API.
Medusa 2.x ships with a module system that makes it idiomatic to add custom modules for things the stock platform doesn’t cover. For the pharmacy build I added five custom modules on top of the stock catalog: brands, bundles, wishlist, reviews, and newsletter. None of these required forking Medusa — they extend it.
Real implementation: the Heartbeat Pharmacy stack
The full stack of the Heartbeat build is:
- Storefront: Next.js 16 App Router + Medusa SDK 2.14, Meilisearch via InstantSearch, PayPal checkout, Turnstile spam protection.
- Storefront API (Medusa backend): Medusa 2.14 with PostgreSQL + Redis + Meilisearch, PayPal payment, Resend email with React Email templates, PostHog analytics, the regulatory pharma-data SOAP integration for master-data lookups.
- PIM backend: Express 5 + TypeORM + Postgres, an embedded MCP server for Claude agents to enrich product descriptions via direct tool calls, Anthropic SDK + Google GenAI for AI-augmented enrichment, BullMQ + Redis queues, S3 for assets.
- PIM admin frontend: React 19 + Vite + TanStack Router/Query/Table/Virtual, the full Radix/shadcn primitive set, Tiptap rich-text editor, dnd-kit drag-and-drop, kbar command palette, Recharts dashboards.
- product-sync Windows Service: Node 22 daemon that syncs the on-site SQL Server (stock + orders) to the remote Medusa API + Skroutz XML feed every 15 minutes, with transactional idempotency, DRY_RUN mode, a LockManager, a CircuitBreaker, and Winston logging.
The whole thing runs on a single Coolify-managed VPS for the dev cycle and is ready to scale horizontally on managed Postgres + a CDN once order volume justifies it.
Greek-specific integrations the stock checkout doesn’t have
A Greek pharmacy needs all of the following to be a real online store. None of them ship with Shopify or with vanilla Medusa.
Piraeus Bank payment gateway
Greek banks issue their own merchant gateways with a redirect-and-callback flow plus signed webhook callbacks. I wrote a Medusa payment plugin that:
- Initiates the payment, redirecting the customer to the bank’s hosted page
- Receives the callback after authorization, validates the signature, and finalizes the order atomically
- Handles refunds idempotently via the bank’s refund endpoint
The same pattern works for Alpha Bank, Eurobank, or NBG — write the plugin once per acquirer, ship it as a private package.
ACS Courier (and the other four)
Each Greek courier exposes a slightly different API. The shipping providers I wired up are ACS, BoxNow, Courier Center, ELTA, and Geniki. The ACS Courier integration was released as open-source on GitHub as a WooCommerce plugin, since several other Greek stores asked for it. The Medusa version follows the same shape.
The shipping plugin for each courier handles: rate quotes at checkout, label generation at order fulfillment, and tracking-number write-back to the order.
Regulatory pharma master-data (SOAP)
Greek pharmacy regulation requires connecting to the country’s regulatory master-data API. Despite the year, this is still a SOAP API. The integration is read-only and pulls master-data for the catalog at scheduled intervals; it doesn’t post anything sensitive. The connection is verified with dedicated test scripts in isolation before production.
Skroutz XML feed
Skroutz is the dominant Greek price-comparison marketplace. Listing on Skroutz requires a strict XML feed with per-SKU availability + price + courier. I generate the feed nightly from the catalog and serve it from a cached endpoint that Skroutz crawls.
When NOT to use Medusa.js
Medusa is the right call for:
- B2C stores that have outgrown Shopify’s fees
- B2B platforms with quote workflows, company hierarchies, and approval flows (Medusa B2B framework)
- Specialty retailers (pharmacy, medical, dental supplies, controlled goods) where an industry-specific regulatory integration is required
- Stores that want to own their checkout and catalog data rather than rent them
Medusa is the wrong call for:
- Stores that just need a fast launch with 5 SKUs — Shopify Basic is faster to set up
- Stores with no dedicated developer — Medusa needs a Node.js engineer to deploy and maintain
- Operations teams that need a no-code marketplace install for every integration — the Medusa ecosystem is real but smaller than Shopify’s
For a Greek pharmacy with thousands of SKUs and recurring transactions, the math came out clearly in favour of owning the stack. For a one-person dropshipping operation it would not.
How to start
If you’re a Greek (or any-non-US) retailer considering the move off Shopify Plus, the order of operations I’d recommend is:
- Audit your transaction fees. Add up the platform percentage on last year’s orders. That’s your annual budget for owning the stack.
- List the integrations you actually need. Most stores list every Shopify app they’ve installed and assume they all need to be ported. They don’t. Most are vestigial.
- Plan the catalog migration. The product, image, and customer export from Shopify is well-documented. A side-by-side launch with the new storefront pointing at the old admin’s exported data is a low-risk way to validate.
- Pick a Greek developer who’s done it before. This stuff is finicky and the cost of one wrong call (signature validation on the bank callback, idempotency on refunds, locking on the inventory sync) is real.
I’ve done the migration before, including all the Greek-specific integrations above. If you’re thinking about it, get in touch.
Related work
- Heartbeat Pharmacy Platform — the full case study of the build above
- Kleidarakos B2B & Papanikolaou Doors — a Medusa B2B build for a Greek locksmith network, with quote workflows and a 3D door configurator
- pooq.gr WooCommerce plugins — when migrating off WooCommerce isn’t the right call, the same Greek integrations as custom WooCommerce plugins instead