1. 01Home
  2. 02About
  3. 03Services
  4. 04Work
  5. 05Blog
  6. 06Contact
TREN
Home/Blog/E-Commerce
E-CommerceJun 2026·7 min read

Medusa V2 How to Set Up a Headless E-Commerce Platform

A comprehensive guide that explains the headless commerce architecture—including product listing, cart, checkout, workflow, and operations layers—end-to-end using Medusa v2.

Medusa V2 Usage: How to Set Up a Headless E-Commerce Infrastructure?

Medusa V2 should be approached differently from the classic “set up a ready-made store and change the theme” approach. The real value here lies in using the commerce core as a separate backend and customizing the storefront, admin experience, and operational workflows according to specific needs. In an e-commerce project, product listing, variant management, cart, payment, inventory, campaigns, and post-order operations are all part of the same system; however, having them all intertwined within the same frontend leads to significant maintenance costs in the long run.

In Medusa v2, the storefront is a separate application. This application can be built using Next.js, React, Vue, or another frontend technology. The storefront sends requests to the Store API routes in the Medusa backend or to the JS SDK. This way, while the design remains entirely yours, commerce behaviors are managed within a more structured core. This separation is particularly important in scenarios that go beyond standard theme logic, such as custom product experiences, editorial landing pages, B2B pricing, gift notes, packaging preferences, or campaign automation.

Understanding the Architecture First

In a headless commerce architecture, there are three main layers: the commerce backend, the storefront, and the operations dashboard. The commerce backend manages product, pricing, inventory, cart, and order rules. The storefront is the user-facing experience. The operations dashboard enables tracking of content, orders, customers, or custom workflows. Separating these three layers allows teams to work more efficiently: while the design team improves the product card, the backend team can work on payment providers, and the operations team can refine the order fulfillment workflow.

Kullanıcı -> Storefront -> Store API / JS SDK -> Medusa Backend -> PostgreSQL / Redis
                                      -> Custom Workflows -> Operasyon / CRM / Bildirim

Storefront Connection

Next.js On the storefront side, the SDK client must be consolidated into a single file. This ensures that the base URL, publishable key, debug settings, and any future common headers remain centralized. Medusa Store API routes are scoped using the publishable API key; therefore, it is crucial to set up key management correctly from the start.

import Medusa from '@medusajs/js-sdk'

const MEDUSA_URL = process.env.NEXT_PUBLIC_MEDUSA_URL || 'http://localhost:9000'

export const sdk = new Medusa({
  baseUrl: MEDUSA_URL,
  debug: process.env.NODE_ENV === "development",
  publishableKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY,
})

This file may seem small, but it defines the project’s boundary. Storefront components do not know direct URLs; they only request product, cart, or customer data through sdk. This discipline simplifies writing tests and switching environments.

Product Listing Strategy

Product listing is not just about “fetching products.” You must determine upfront which fields are needed on the list page: image, title, price, discount information, category, number of variants, stock status, and short description. If the price is to be displayed on the card, price calculation fields should be considered; if there are filters, category and tag fields; and if there is a product story, metadata fields should be considered.

export async function listProducts(regionId: string, query?: string) {
  const { products, count } = await sdk.store.product.list({
    region_id: regionId,
    q: query,
    limit: 24,
    fields: "*variants.calculated_price,+metadata,+tags",
  })

  return { products, count }
}

Here, using the fields parameter intentionally is valuable for performance. Fetching unnecessary data bloats the list page; fetching insufficient data creates additional requests per card. The best solution is to translate the information visible in the design into data requirements.

Cart and Checkout

The cart state is typically stored on the user’s device using a cart ID. However, the actual cart data resides in the backend. Therefore, the cart ID is stored in the frontend, but line items, totals, shipping, and payment calculations are kept up-to-date on the Medusa side. Cart update operations can feel faster with an optimistic UI, but the backend response must always be treated as the single source of truth.

export async function addLineItem(cartId: string, variantId: string, quantity = 1) {
  return sdk.store.cart.createLineItem(cartId, {
    variant_id: variantId,
    quantity,
  })
}

export async function setLineItemQuantity(cartId: string, lineId: string, quantity: number) {
  return sdk.store.cart.updateLineItem(cartId, lineId, { quantity })
}

Customization with Workflow

One of the strengths of Medusa v2 is its workflow approach. You can add custom business rules before or after the standard order flow. For example, processes such as gift note validation, creating a custom packaging task, generating an out-of-stock notification, or logging a post-order activity in CRM can be modeled using workflows.

import { createWorkflow, WorkflowResponse } from '@medusajs/framework/workflows-sdk'

type Input = {
  orderId: string
  giftNote?: string
  packageType?: "standard" | "premium"
}

export const prepareOrderWorkflow = createWorkflow('prepare-order', (input: Input) => {
  // 1. Siparişi oku
  // 2. Özel alanları doğrula
  // 3. Operasyon görevi oluştur
  // 4. Bildirim veya CRM entegrasyonunu tetikle
  return new WorkflowResponse({ order_id: input.orderId })
})

Conclusion

When using Medusa v2, the key issue isn’t “can I list products?” but rather how clearly you’ve divided commerce behaviors into distinct boundaries. The storefront preserves design freedom, Medusa manages commerce rules, and the workflow layer translates business-specific processes into the system. When this trio is set up correctly, an e-commerce project becomes not just a sales interface but a scalable operational infrastructure.

Key Details to Consider in Practice

The most common mistake in e-commerce infrastructure is designing the user interface in isolation from commerce rules. The price displayed on the product card must be sourced from the same data source as the price calculated in the cart total. When variant selection, stock status, region-based currency, and discount information are not linked to the same data model, the user interface loses credibility. Therefore, it is essential to define a clear source in the backend for every piece of information displayed in the design.

Another critical point is the caching strategy. Product listing pages can be cached; however, greater caution is required in areas such as the cart, checkout, stock alerts, and personalized pricing. A balance must be struck between static loading speed and the accuracy of live data. Especially during promotional periods, incorrect pricing or stock information is a far greater issue than performance problems.

Test Scenarios

Before going live, you should not test only the successful flow. What happens when a variant is out of stock? What does the user see if the payment session cannot be refreshed? How does checkout behave if there are no shipping options? Is the message clear if a discount code is invalid? These questions must be included in the test plan.

Metrics

Measuring success solely by order count is insufficient. The product-to-cart conversion rate, cart abandonment rate, drop-off rates by checkout step, payment error rate, and mobile conversion rate should all be tracked together. These metrics help improve both design and infrastructure decisions.

Implementation Plan

When applying this approach to a real project, start by building a small but fully functional core. The first step should be to clarify the data model, the second step to define the API contract, and the third step to complete the main user flow in the interface. Afterward, additional layers such as automation, translation, reporting, or media management can be added sequentially. Proceeding this way maintains development speed while preventing complexity from growing too early.

Additionally, every technical decision must have a user or operational justification. A table, queue, SDK, or dashboard component should be added not merely because it is technically correct, but because it makes the process more understandable, faster, or more measurable. Robust products grow through this discipline.

Medusa v2Next.jsHeadless CommercePostgreSQLRedis
Share

0 Comments

Leave a comment

I'm not a robot reCAPTCHA