Headless commerce is not just decoupling for the sake of decoupling. It is a way to ship faster, scale without rewriting, and avoid platform lock-in — while still giving marketing teams a CMS that does not require a developer for every landing page update.
In this guide, we build the architecture (and the mental model) for a stack we use a lot at Adeptive:
MedusaJS = commerce engine (products, carts, orders, promotions). Stripe = payments (Checkout or Payment Intents). Sanity = content (pages, campaigns, editorial, rich product storytelling). Next.js = storefront (SEO, performance, UI/UX freedom).
What headless commerce means (in practical terms)
Headless commerce separates your system into clear layers: commerce backend (products, pricing, inventory, cart, orders, discounts), content backend (editorial, landing pages, navigation, SEO copy, campaigns), frontend (the customer experience — fast, SEO-friendly, brand-specific), and integrations (payments, shipping, ERP, CRM, email, search).
This separation gives you one huge advantage: you can change one layer without rewriting the others.
Why Sanity + Medusa + Next.js + Stripe is a strong combo
Sanity: content you can model, reuse, and ship fast
Sanity shines when you need campaign landing pages, editorial collections (not just categories), rich storytelling around products, and reusable content blocks (testimonials, trust badges, USPs).
MedusaJS: commerce primitives without the platform tax
Medusa gives you products and variants, cart and order lifecycle, promotions and discounts, an admin plus API surface you control, and extensibility via plugins and custom endpoints.
Next.js: storefront freedom + SEO + performance
You get full control over URL structure, metadata, schema.org markup, SSR/SSG/ISR, edge caching patterns, and a composable UI.
Stripe: the payment system you will integrate anyway
Stripe is the default choice for many modern headless builds: global payment methods, strong developer tooling, Checkout for speed, Payment Intents for custom UX, and webhooks for reliable reconciliation.
Reference architecture (who owns what)
A split that stays maintainable:
Sanity owns: home page hero content, campaign landing pages, editorial collections (Spring Edit, Gifts under 50), navigation and footer, SEO copy blocks, trust content (reviews, guarantees, delivery info).
Medusa owns: products, variants, prices, availability and inventory logic, carts, orders, returns, promotions, gift cards, fulfillment and shipping integrations.
Stripe owns: payment authorization and capture, payment methods, Checkout sessions and PaymentIntents, webhook events (payment succeeded or failed).
Next.js owns: rendering, routing, and performance, product and category pages (composed from Medusa and Sanity), editorial pages from Sanity, tracking and consent handling.
The core data flows (the part people usually get wrong)
Flow A — Product listing page
Next.js fetches products from Medusa (/store/products). Next.js fetches editorial modules from Sanity (banner, copy blocks). Next.js merges them into a page that is both sellable and SEO-friendly.
Flow B — Add to cart
Next.js calls Medusa to create or update a cart. Cart state lives in your frontend, but Medusa is the source of truth.
Flow C — Checkout
Two common approaches work well with this stack: Stripe Checkout (fastest path to launch) and Payment Intents (full control). Your decision should be driven by conversion goals and UX constraints — not by preference.
Option 1: Stripe Checkout (fastest to ship)
Use Stripe Checkout Sessions when you want to launch quickly and let Stripe handle localization, payment method UX, and a lot of edge cases (3DS, retries, etc.). You still keep a clean order lifecycle in Medusa via webhooks.
Option 2: Payment Intents (full custom UX)
Use Payment Intents when checkout UX is a competitive advantage and you need tight control over every step (upsells, shipping logic, address validation, experiments). It’s more work, but it’s the right call for mature products.
Implementation blueprint (step-by-step)
Step 1 — Start with a clear repo layout
A pragmatic structure is: apps/storefront (Next.js), apps/medusa (commerce backend), apps/sanity (Sanity Studio), and packages/shared (types + utilities).
Step 2 — Model content in Sanity (don’t just dump rich text)
Create document types for page, landingPage, navigation, and editorial collections. Build reusable blocks (USPs, testimonials, FAQ, trust badges) so marketing can ship without dev help.
Step 3 — Configure Medusa for pricing + regions early
Set up regions, currencies, shipping methods, and promotion rules before you polish the frontend. Most “mystery bugs” later are actually pricing/region mismatches.
Step 4 — Integrate Stripe + webhooks (idempotent by default)
Treat Stripe webhooks as the source of payment truth. Build idempotent handlers and map events to Medusa order state transitions (created → payment pending → paid/failed).
Step 5 — Compose pages in Next.js (content + commerce)
Fetch commerce primitives from Medusa and editorial modules from Sanity on the server (SSR/ISR). Merge them into one page tree to avoid client-side waterfalls and keep SEO strong.
Checkout: Stripe Checkout vs Payment Intents (a decision framework)
Default to Stripe Checkout for MVPs. Move to Payment Intents only when you have a specific, measured reason (conversion experiments, complex shipping logic, or product-led checkout UX).
SEO + performance (how to not lose the headless advantage)
SEO basics: stable human URLs, canonical tags, schema.org for Product + BreadcrumbList, and metadata managed in Sanity but validated in code.
Performance basics: cache Medusa reads where safe, optimize images (Sanity + Next Image), and keep above-the-fold data server-rendered to avoid hydration waterfalls.
Common pitfalls (and how to avoid them)
1) Two sources of truth for product copy — decide what lives in Medusa vs Sanity and stick to it.
2) Non-idempotent webhooks — Stripe retries; your handlers must be safe to run multiple times.
3) Content models that don’t match UI components — editors will fight the CMS instead of using it.
4) Over-custom checkout too early — ship Checkout first, then optimize with real data.
Launch checklist
Sanity: content models + navigation + SEO. Medusa: regions, shipping, taxes. Stripe: checkout flow + webhooks. Next.js: SSR/ISR strategy, sitemap, robots, schema. Monitoring: webhook failures + order/payment mismatches.