Ecommerce Platforms
February 19, 2026
22 min read

Next.js + Medusa.js + Meilisearch: The Modern Ecommerce Tech Stack That Replaces $2,000/Month in SaaS

I built this stack because I was tired of paying $2,000/month in SaaS fees for tools that gave me less control than a $40/month VPS. Next.js for the frontend, Medusa.js for the commerce backend, Meilisearch for product search. Three open-source tools that, combined, outperform Shopify + Algolia on every metric I care about: page speed, SEO control, search relevance, and total cost of ownership. This is the architecture I run for my own projects and recommend to every ecommerce operator who has outgrown their platform.

Aditya Aman
Aditya Aman
Founder & Ecommerce SEO Consultant

1. Why This Stack Exists

The modern ecommerce tech stack I am about to walk you through exists because SaaS platforms charge you a recurring tax on your own revenue while giving you a fraction of the control you need. A Shopify store doing $50K/month pays $79 for the plan, $1,450 in transaction fees (2.9%), $200-500 in apps (reviews, upsells, email, SEO tools), and $200+ for a premium theme. That is $1,930-2,230 every month for a platform that will not let you customize your URL structure, caps your page speed at 3+ seconds due to mandatory platform JavaScript, and locks your data inside their walled garden.

I hit this wall with a D2C beauty client in 2024. Their Shopify store was doing $80K/month but bleeding $2,800/month in platform and app costs. Their LCP was stuck at 3.4 seconds no matter what we optimized because Shopify's Liquid rendering engine and mandatory analytics scripts create a performance floor you cannot break through. Their search was powered by a $480/month Algolia integration that returned irrelevant results for ingredient-based queries.

We rebuilt on Next.js + Medusa.js + Meilisearch. Infrastructure cost dropped to $60/month. LCP dropped to 1.2 seconds. Search relevance for ingredient queries improved from 34% accuracy to 91%. The migration paid for itself in 6 weeks through eliminated SaaS fees alone, before counting the conversion rate lift from faster pages.

This is not a theoretical architecture. I run it, I maintain it, and I have watched it outperform every hosted platform I have worked with across the metrics that actually matter for ecommerce growth. Here is how every piece works and how they connect.

2. Architecture Overview: How the Three Pieces Connect

The architecture follows a clean separation of concerns: Medusa.js handles commerce logic (products, orders, customers, payments), Next.js renders the storefront and handles SEO, and Meilisearch powers product search and filtering. Each component communicates through REST APIs, and each one can be replaced independently without touching the others.

This is the core of composable commerce and MACH architecture applied to a real, production-ready stack. Not the buzzword version that enterprise consultants sell for $50K. The practical version that runs on a $40 VPS.

The data flow works like this: Medusa.js is the source of truth for all product data. When a product is created or updated in the Medusa admin, a webhook fires to sync that data to Meilisearch's search index. Next.js fetches product data from Medusa's REST API for page rendering (using ISR for sub-second page loads) and queries Meilisearch directly for search and filtering. The user's browser never talks to Medusa or Meilisearch directly.

  • Medusa.js (Port 9000): Commerce API, admin dashboard, order management, payment processing
  • Meilisearch (Port 7700): Search index, typo-tolerant queries, faceted filtering, sub-50ms responses
  • Next.js (Port 3000 / Vercel): Server-rendered storefront, ISR product pages, SEO metadata, structured data
  • PostgreSQL: Medusa's database for products, orders, customers
  • Redis: Session storage and caching layer for Medusa

3. Medusa.js: The Commerce Backend You Actually Own

Medusa.js is an open-source, Node.js-based commerce backend that gives you everything Shopify does, without the monthly tax or the technical ceiling. Products, variants, collections, orders, customers, discounts, gift cards, payments, fulfillment, tax calculation, multi-currency, multi-region. All through a REST API and an admin dashboard that your operations team can use without touching code.

The architecture decision that makes Medusa the right choice over Saleor, Vendure, or other open-source alternatives comes down to three factors. First, it is Node.js/TypeScript end-to-end, which means your entire stack runs one language. Second, its plugin system is genuinely modular. You install a Stripe plugin for payments, a SendGrid plugin for email, and each one is a self-contained npm package. Third, the admin dashboard ships out of the box and is production-ready.

From an SEO perspective, Medusa gives you what Shopify never will: complete control over your data model. You define your product slugs. You control which fields are exposed through the API. You can add custom attributes (ingredient lists, skin type compatibility, application instructions) that feed directly into your Next.js frontend for structured data and on-page SEO content. No app required, no monthly fee, no limitations on schema complexity.

Setting Up Medusa for Production

A production Medusa setup requires a VPS with at least 2GB RAM (4GB recommended for stores with 5,000+ SKUs), PostgreSQL 14+, and Redis 7+. I run all three on a single Hetzner CX31 instance at $15.90/month for stores under 10,000 SKUs. The Medusa server itself consumes roughly 200-400MB of RAM at idle, PostgreSQL takes 300-500MB, and Redis uses 50-100MB. This leaves headroom for traffic spikes.

# Install Medusa CLI and create a new project
npx create-medusa-app@latest my-store

# Project structure after scaffolding:
# my-store/
#   backend/          <- Medusa server (Node.js)
#   storefront/       <- Next.js frontend (we replace this)
#
# Configure environment variables
# backend/.env
DATABASE_URL=postgresql://user:pass@localhost:5432/medusa
REDIS_URL=redis://localhost:6379
JWT_SECRET=your-jwt-secret
COOKIE_SECRET=your-cookie-secret
STORE_CORS=http://localhost:3000
ADMIN_CORS=http://localhost:7001

# Start the backend
cd my-store/backend
medusa develop

4. Next.js: The Frontend That Google Loves

Next.js is the frontend layer that turns Medusa's API data into server-rendered HTML that search engines can crawl, index, and rank. The reason I chose Next.js over Remix, Nuxt, or SvelteKit is not that those frameworks are inferior. It is that Next.js has the largest ecommerce-specific tooling, the most mature deployment infrastructure (Vercel), and Incremental Static Regeneration for product pages that gives you static-site speed with dynamic-site freshness.

For site speed optimization, ISR is the single most important architectural decision in this stack. Every product page is statically generated at build time and served from a CDN edge node. When a product price changes in Medusa, a webhook triggers on-demand revalidation, and the next visitor gets the updated page without any perceptible delay. TTFB on ISR pages is consistently under 100ms globally because the HTML is pre-built and cached at the edge.

Server Components in Next.js App Router are the other critical SEO win. Your product page component runs entirely on the server. The browser receives fully-rendered HTML with all product titles, descriptions, prices, and schema markup present in the initial response. Googlebot sees your complete page without executing JavaScript. For stores with 5,000+ product pages, this eliminates the rendering budget problem that headless commerce SEO guides warn about.

Product Page Architecture in Next.js

The product page is the revenue center of your store. Here is the exact architecture I use for the dynamic product route that fetches from Medusa and generates SEO metadata:

// app/products/[slug]/page.tsx
import { Metadata } from 'next'
import { notFound } from 'next/navigation'

// ISR: revalidate every 60 minutes, on-demand via webhook
export const revalidate = 3600

// Pre-generate all product pages at build time
export async function generateStaticParams() {
  const { products } = await fetch(
    `${process.env.MEDUSA_URL}/store/products?limit=1000`,
    { headers: { 'x-publishable-api-key': process.env.MEDUSA_KEY! } }
  ).then(r => r.json())

  return products.map((p: { handle: string }) => ({
    slug: p.handle,
  }))
}

// Dynamic SEO metadata from Medusa product data
export async function generateMetadata({
  params,
}: {
  params: Promise<{ slug: string }>
}): Promise<Metadata> {
  const { slug } = await params
  const { products } = await fetch(
    `${process.env.MEDUSA_URL}/store/products?handle=${slug}`,
    { headers: { 'x-publishable-api-key': process.env.MEDUSA_KEY! } }
  ).then(r => r.json())

  if (!products?.length) return {}
  const product = products[0]

  return {
    title: `${product.title} | YourStore`,
    description: product.description?.slice(0, 155),
    alternates: { canonical: `/products/${slug}` },
    openGraph: {
      title: product.title,
      description: product.description,
      images: [{ url: product.thumbnail, width: 1200, height: 630 }],
    },
  }
}

export default async function ProductPage({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = await params
  const { products } = await fetch(
    `${process.env.MEDUSA_URL}/store/products?handle=${slug}`,
    { headers: { 'x-publishable-api-key': process.env.MEDUSA_KEY! },
      next: { revalidate: 3600 } }
  ).then(r => r.json())

  if (!products?.length) notFound()
  const product = products[0]

  return (
    <>
      <ProductJsonLd product={product} />
      <ProductTemplate product={product} />
    </>
  )
}

Meilisearch replaces the $500-2,000/month Algolia bill with a self-hosted search engine that returns results in under 50ms, handles typos out of the box, and supports faceted filtering for every product attribute in your catalog. I have run it on stores with 50,000+ SKUs and the response time stays under 30ms. The entire binary is 50MB and runs on 256MB of RAM for catalogs under 100,000 documents.

What convinced me to switch from Algolia was not just cost. It was search relevance for niche ecommerce queries. On a beauty store, customers search for "niacinamide serum for oily skin" not "serum SKU-4532." Meilisearch's ranking rules let you prioritize matches in the product title, then ingredients, then description, then tags. You define the hierarchy once, and every search query respects it. Algolia can do this too, but the configuration is buried behind a $249/month plan and requires their dashboard to manage.

The typo tolerance is genuinely good. A customer typing "hyalronic acid" instead of "hyaluronic acid" gets the right results on the first keystroke. This is critical for beauty, supplements, and any vertical where product names include scientific or technical terms that buyers frequently misspell.

Syncing Medusa Products to Meilisearch

The sync between Medusa and Meilisearch happens through a subscriber that listens for product events. When a product is created, updated, or deleted in Medusa, the subscriber pushes the change to Meilisearch's index. Initial sync for 5,000 products takes about 3 seconds. Incremental updates are near-instant.

// medusa-config.ts  -  Register the Meilisearch plugin
module.exports = {
  plugins: [
    {
      resolve: 'medusa-plugin-meilisearch',
      options: {
        config: {
          host: process.env.MEILISEARCH_HOST || 'http://127.0.0.1:7700',
          apiKey: process.env.MEILISEARCH_API_KEY,
        },
        settings: {
          products: {
            indexSettings: {
              searchableAttributes: [
                'title',
                'description',
                'variant_sku',
                'collection_title',
              ],
              filterableAttributes: [
                'collection_id',
                'type_value',
                'tags',
                'variant_prices.amount',
              ],
              sortableAttributes: [
                'created_at',
                'variant_prices.amount',
              ],
              rankingRules: [
                'words',
                'typo',
                'proximity',
                'attribute',
                'sort',
                'exactness',
              ],
            },
            primaryKey: 'id',
            transformer: (product: Record<string, unknown>) => ({
              id: product.id,
              title: product.title,
              handle: product.handle,
              description: product.description,
              thumbnail: product.thumbnail,
              collection_title: (product.collection as Record<string, unknown>)?.title,
              collection_id: product.collection_id,
              type_value: (product.type as Record<string, unknown>)?.value,
              tags: (product.tags as Array<Record<string, unknown>>)?.map(
                (t) => t.value
              ),
              variant_prices: (product.variants as Array<Record<string, unknown>>)?.flatMap(
                (v) => (v.prices as Array<Record<string, unknown>>) || []
              ),
            }),
          },
        },
      },
    },
  ],
}

6. Connecting the Stack: API Routes and Data Flow

The three components talk to each other through a straightforward API pattern. Next.js is the orchestration layer: it calls Medusa for commerce data (products, cart, checkout) and Meilisearch for search queries. The browser talks only to Next.js. This keeps your Medusa and Meilisearch instances behind a firewall, which is both a security and performance advantage.

For search, the Next.js frontend sends the user's query to a Next.js API route, which proxies it to Meilisearch and returns formatted results. This proxy pattern lets you add rate limiting, analytics tracking, and query logging without exposing your Meilisearch instance to the public internet.

For cart and checkout, Next.js calls Medusa's storefront API directly from Server Components (for initial page load) and from client-side fetch calls (for add-to-cart, quantity changes, and checkout steps). Medusa handles all payment processing through its Stripe plugin. The checkout flow never leaves your domain.

The on-demand revalidation webhook is what keeps everything in sync for SEO. When an admin updates a product price in Medusa's dashboard, Medusa fires a webhook to a Next.js API route that calls revalidatePath('/products/[slug]'). Within 1-2 seconds, the CDN-cached static page is regenerated with the new price. Your structured data is always accurate, which is critical for Product schema compliance and Google Merchant Center eligibility.

7. Cost Comparison: This Stack vs SaaS Alternatives

The cost advantage of this stack is not marginal. It is a 10-20x reduction in monthly infrastructure costs compared to the equivalent SaaS tooling. Here is the breakdown at three revenue tiers, with real numbers from stores I have built or migrated.

Monthly Cost Comparison: Self-Hosted vs SaaS at $50K/Month Revenue

ComponentNext.js + Medusa + MeilisearchShopify + AlgoliaBigCommerce + Algolia
Commerce Platform$0 (open source)$79/mo (Basic) or $2,300/mo (Plus)$299/mo (Pro)
Hosting / Infrastructure$20-40/mo (VPS)IncludedIncluded
Frontend Hosting$0-20/mo (Vercel)IncludedIncluded
Search$0 (self-hosted Meilisearch)$249-499/mo (Algolia)$249-499/mo (Algolia)
Transaction Fees2.9% Stripe ($1,450)2.9% + platform fee ($1,450+)2.9% ($1,450)
Apps / Plugins (reviews, email, SEO)$0-30/mo (open source or free tiers)$200-500/mo$100-300/mo
Total (excl. transaction fees)$20-90/mo$528-3,299/mo$648-1,098/mo
Annual SavingsBaseline$5,256-38,508 more$6,696-12,096 more

Based on a store with 2,000 SKUs, 50K monthly sessions, $50K monthly revenue. SaaS app costs vary by specific tools selected.

The honest caveat: you trade monthly SaaS cost for upfront development time. A production-ready store on this stack takes 40-80 hours of developer time to build. At a $100/hour developer rate, that is $4,000-8,000 in initial build cost. But the math still works overwhelmingly in favor of self-hosting: at $500/month in SaaS savings (the conservative end), the build cost is recovered in 8-16 months. At $2,000/month savings (the Shopify Plus tier), you break even in 2-4 months.

8. Performance Benchmarks

Performance is where this stack creates the widest gap over SaaS platforms. When you eliminate platform JavaScript overhead, theme rendering engines, and third-party app injection, the baseline performance of your store drops to near-theoretical minimums.

Core Web Vitals Benchmarks: Self-Hosted vs Platform Stores

MetricNext.js + Medusa (ISR)Shopify (Dawn theme)WooCommerce (optimized)BigCommerce
LCP (mobile)1.1-1.4s2.8-4.2s2.2-3.8s2.5-3.5s
INP (mobile)80-120ms180-350ms200-500ms160-280ms
CLS0-0.020.05-0.150.08-0.250.04-0.12
TTFB50-120ms400-900ms300-1,200ms350-800ms
Total JS Bundle85-140KB300-600KB400-900KB250-500KB
Lighthouse Performance95-10045-7235-6550-75

Measured on product pages with 5+ images, review widget, and related products section. Mobile scores on Moto G Power (4G throttled). Shopify scores include 3-4 typical apps installed.

The TTFB difference is the most dramatic and the hardest for SaaS platforms to close. ISR pages on Vercel or Cloudflare Pages serve from the edge with no server computation. The HTML is pre-built and cached globally. Shopify's Liquid rendering engine processes every request through their server, which adds 400-900ms before the browser receives a single byte.

The JavaScript bundle difference is equally significant for INP. A Next.js storefront with Server Components sends only the JavaScript needed for interactivity (cart button, variant selector, image gallery). Everything else renders on the server and ships as HTML. Shopify themes load their entire JavaScript bundle on every page, including code for features the current page does not use. That dead JavaScript still parses and executes, blocking the main thread and degrading INP.

9. SEO Advantages of Owning Your Stack

SEO control is the least-discussed but highest-value advantage of running your own stack. On Shopify, you cannot change product URL prefixes from /products/. You cannot generate a custom sitemap that includes image elements with product photography alt text. You cannot implement hreflang tags without an app. You cannot add custom schema types beyond what your theme supports. Every one of these limitations has a measurable SEO cost.

With Next.js, you own your URL structure completely. Your product pages live at /blue-running-shoes if you want flat URLs, or /running-shoes/nike-air-max-270 if you want category-nested paths. Your sitemap is a TypeScript file that pulls product URLs from Medusa and generates exactly the XML Google needs, with lastmod timestamps from your actual product update dates, not arbitrary refresh intervals.

Structured Data Without Platform Limitations

On this stack, your structured data is pure TypeScript that generates JSON-LD from your Medusa product data. You implement Product schema with every field Google supports: variants, offers, aggregate rating, individual reviews, brand, category, ingredient lists, pros/cons. On Shopify, your schema is limited to what the theme or a $15/month app provides. I have audited 40+ Shopify stores and found broken schema on 34 of them because the theme's schema template could not handle their specific product data structure.

Internal Linking Architecture You Control

Internal linking is where platform stores lose the most organic visibility. On Shopify, you cannot programmatically add contextual internal links between related products, from collection pages to buying guides, or from blog posts to specific product variants. On this stack, you build your internal linking logic in Next.js components: related product sections pull from Medusa collections, breadcrumbs generate from your category hierarchy, and blog content links to product pages with exact anchor text you control.

The search data from Meilisearch adds another SEO advantage most stores miss entirely. Your search analytics reveal exactly what customers are searching for on your store. When 200 people search for "vitamin C serum for dark spots" and find nothing, that is a content gap you can fill with a new product or a buying guide that targets that exact query. Algolia provides this data too, but only on their $249+ plans. With Meilisearch, you own the search logs and can pipe them into any analytics tool you want.

10. When NOT to Use This Stack

This stack is not for everyone, and I want to be direct about who should not use it. If you are launching your first ecommerce store, have zero developer experience, and your product catalog is under 100 SKUs, start with Shopify. The $79/month is worth it for the speed of getting to market. You can always migrate later when the SaaS costs start eating into your margins.

If your team has no JavaScript or TypeScript experience and no budget to hire a developer, this stack will frustrate you. Medusa.js has a learning curve. Next.js requires understanding of React, server components, and deployment. Meilisearch is the simplest of the three, but you still need to manage a server. The admin dashboard handles day-to-day operations, but anything beyond adding products and managing orders requires code.

If you need same-day launch, a SaaS platform is the right call. A Shopify store can be live in 48 hours. This stack takes 2-4 weeks for a production-ready store. The investment is worth it for the long game, but if you have inventory arriving next week and need to start selling, do not try to build a custom stack under time pressure.

The sweet spot for this stack is stores doing $20K-500K/month with at least one person on the team who can write JavaScript, or the budget to hire a developer for 5-10 hours/month of maintenance. At that revenue level, the SaaS savings fund the developer cost with money left over, and the performance and SEO advantages compound into measurable organic growth.

FAQ

Next.js + Medusa + Meilisearch Stack FAQs

For a store with up to 10,000 SKUs and 50,000 monthly sessions, expect $40-80/month in infrastructure costs. That breaks down to $20-40/month for a VPS running Medusa.js and Meilisearch (Hetzner, DigitalOcean, or Railway), $0 for Next.js hosted on Vercel's free tier or $20/month on the Pro plan, and Stripe processing fees at 2.9% + $0.30 per transaction. The equivalent SaaS stack (Shopify + Algolia + premium theme + apps) runs $800-2,400/month at the same scale.
You need developer involvement for initial setup (40-80 hours for a production-ready store) and for feature development. Day-to-day store operations like adding products, managing orders, and updating content happen through Medusa's admin dashboard, which is comparable to Shopify's admin panel. A solo founder who can write basic JavaScript can maintain it after initial setup. For stores doing $50K+/month, having a part-time developer on retainer (5-10 hours/month) is recommended for updates, monitoring, and feature additions.
This stack gives you more SEO control than Shopify in every measurable category. You control your URL structure completely (no forced /products/ or /collections/ prefixes). You can implement any schema markup pattern without app limitations. Your page speed ceiling is dramatically higher because there is no platform JavaScript overhead. You own your sitemap generation logic. The trade-off is that you must implement these features yourself, whereas Shopify provides basic versions out of the box. For a detailed breakdown, see our headless commerce SEO guide.
Meilisearch covers 90% of what ecommerce stores actually use from Algolia: typo tolerance, faceted filtering, synonyms, stop words, geo search, and sub-50ms response times. The 10% gap is in advanced features like AI-powered recommendations, A/B testing on search results, and analytics dashboards. For stores under $500K/month in revenue, that 10% gap rarely justifies the $500-2,000/month Algolia bill. If you need those advanced features, you can add them later without changing the rest of your stack.
Medusa.js supports multiple payment providers through its plugin system. Use Stripe as your primary gateway for North America and Europe, Razorpay for India, Paystack for Africa, and Mollie for additional European payment methods. Each gateway is a separate Medusa plugin that you install and configure independently. You can run multiple payment providers simultaneously for different regions. This is one area where the composable approach genuinely outperforms Shopify, which limits your payment options unless you are on Shopify Plus.
Both are open-source projects with active communities and commercial backing. Medusa.js has raised $20M+ in venture funding and has 25,000+ GitHub stars. Meilisearch has raised $30M+ and has 48,000+ GitHub stars. But the deeper answer is that open-source risk is lower than SaaS risk. If Medusa disappears, you still own your code and data. You can fork the project or migrate to another Node.js commerce framework. If Shopify raises prices or changes policies, you have no code, no data portability, and no alternative that does not require a full rebuild.
If you have developer resources and are building a new store, start with this stack. The upfront investment pays for itself within 6-12 months through eliminated SaaS fees and better performance metrics. If you are already running a Shopify store doing under $20K/month with no developer on the team, stay on Shopify and focus on growing revenue. Migrate when the monthly SaaS costs exceed $500/month and you have developer capacity. The migration itself takes 2-4 weeks for a store with under 5,000 SKUs.

Where to Start: The 3-Step Migration Path

If you are running a SaaS ecommerce store and the numbers in this article made you uncomfortable, here is the progression I recommend. First, spin up a Medusa.js instance on a $10/month VPS and mirror your existing product catalog into it. This takes 2-4 hours and gives you a feel for the admin interface and API. Second, build a single product page in Next.js that fetches from Medusa and compare the Lighthouse score to your current store. The performance gap will be self-evident. Third, add Meilisearch and test search relevance against your current search tool.

You do not need to migrate everything at once. The composable nature of this stack means you can adopt it incrementally. Run Meilisearch alongside your existing Shopify search for a month to validate relevance. Build a headless Next.js frontend that points to your existing commerce backend before switching to Medusa.

The stores that outperform on organic search in 2026 are the ones that control their own technical infrastructure. Every month you pay a SaaS platform for suboptimal page speed, restricted URL structures, and limited schema markup is a month your competitors on owned stacks are compounding their SEO advantages. The migration cost is a one-time investment. The SaaS tax is forever.

Get Your Free Ecommerce SEO Audit

I audit ecommerce stores and deliver a prioritized list of SEO fixes with revenue impact calculated for each item. Whether you are on Shopify, WooCommerce, or already running a headless stack, I will show you exactly where you are leaving organic revenue on the table and what to fix first.

Aditya went above and beyond to understand our business needs and delivered SEO strategies that actually moved the needle.
Wendy Chan
Co-Founder & CEO, PackMojo

Related Articles

Why Medusa.js is the strongest open-source alternative to Shopify for teams that want complete ownership of their commerce backend, data, and SEO architecture.

How to replace $500+/month Algolia bills with self-hosted Meilisearch. Covers typo tolerance, faceted filtering, and search-to-SEO content gap discovery.

The complete SEO playbook for headless commerce stores. Covers rendering strategy, structured data, sitemap generation, and the mistakes that tank organic traffic.

A practical guide to MACH architecture for ecommerce. Covers when composable commerce pays for itself and when a simpler setup is the better call.

Next.js + Medusa.js + Meilisearch: The Modern Ecommerce Tech Stack That Replaces $2,000/Month in SaaS | EcommerceSEO