Skip to main content
Back to Articles
MagentoJune 10, 20259 min read

Magento 2 Headless Commerce Architecture Guide

Architect a headless Magento 2 storefront with a decoupled frontend, GraphQL API layer, and microservices for scalable modern commerce experiences.

Why Go Headless

Traditional Magento 2 architecture couples the frontend theme layer directly to the backend PHP application. Every page request passes through the Magento rendering pipeline — layout XML, blocks, templates, and KnockoutJS components. This architecture served well for years, but modern commerce demands faster storefronts, omnichannel experiences, and independent frontend deployment cycles.

Headless commerce separates the presentation layer from the commerce engine. The Magento 2 backend becomes a pure API server handling catalog, cart, checkout, and order management, while a dedicated frontend framework delivers the customer experience.

Architecture Overview

A production headless Magento 2 setup consists of several layers:

Frontend Layer: A Next.js or React application deployed on edge infrastructure (Vercel, CloudFront, or a Kubernetes cluster). This handles all rendering — either server-side (SSR) or static (SSG) — and communicates with the backend exclusively through APIs.

API Gateway: An NGINX or AWS API Gateway layer that routes requests, handles rate limiting, and manages authentication tokens. This sits between the frontend and the Magento backend.

Commerce Engine: Magento 2 running in API-only mode with the storefront theme disabled. GraphQL and REST endpoints serve product data, cart operations, and checkout flows.

Services Layer: Microservices for search (Elasticsearch/OpenSearch), payments (Stripe/Adyen), and content (headless CMS like Contentful or Strapi).

Setting Up the GraphQL API

Magento 2 ships with a comprehensive GraphQL API. Enable it and configure the schema for headless use:

// app/etc/env.php
'system' => [
    'default' => [
        'web' => [
            'graphql' => [
                'cors_allowed_origins' => 'https://store.example.com',
                'cors_allowed_methods' => 'GET,POST,OPTIONS',
                'cors_max_age' => 86400,
            ],
        ],
    ],
],

Product Query Example

query GetProductPage($urlKey: String!) {
  products(filter: { url_key: { eq: $urlKey } }) {
    items {
      sku
      name
      price_range {
        minimum_price {
          final_price { value currency }
          discount { percent_off }
        }
      }
      media_gallery {
        url
        label
      }
      description { html }
      related_products {
        sku
        name
        thumbnail { url }
      }
    }
  }
}

Frontend Architecture with Next.js

Build the storefront with Next.js for optimal performance through server-side rendering and static generation:

// lib/magento-client.ts
const MAGENTO_GRAPHQL_URL = process.env.MAGENTO_GRAPHQL_URL!;

export async function magentoFetch<T>(
  query: string,
  variables?: Record<string, unknown>
): Promise<T> {
  const response = await fetch(MAGENTO_GRAPHQL_URL, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Store: "default",
    },
    body: JSON.stringify({ query, variables }),
    next: { revalidate: 60 },
  });
  const json = await response.json();
  if (json.errors) throw new Error(json.errors[0].message);
  return json.data;
}

Static Generation for Category Pages

export async function generateStaticParams() {
  const data = await magentoFetch<CategoryData>(
    `{ categories(filters: {}) { items { url_path children { url_path } } } }`
  );
  return data.categories.items.flatMap((cat) =>
    [cat, ...cat.children].map((c) => ({ slug: c.url_path.split("/") }))
  );
}

Caching Strategy

Implement multi-layer caching for performance:

CDN Layer: Cache product listing pages and category pages at the CDN edge with 60-second TTL. Use stale-while-revalidate headers to serve cached content while fetching fresh data.

Application Layer: Use Next.js ISR (Incremental Static Regeneration) with on-demand revalidation triggered by Magento webhooks when products or prices change.

API Layer: Deploy Varnish or Redis in front of the Magento GraphQL endpoint. Cache GET-equivalent POST requests using query hashing.

Handling Cart and Checkout

Cart operations are stateful and require careful session management in a headless context:

// Create guest cart
const { createEmptyCart } = await magentoFetch<{ createEmptyCart: string }>(
  `mutation { createEmptyCart }`
);
// Store cart ID in HTTP-only cookie
cookies().set("cart_id", createEmptyCart, {
  httpOnly: true,
  secure: true,
  sameSite: "strict",
  maxAge: 60 * 60 * 24 * 30,
});

Performance Benchmarks

A well-implemented headless Magento 2 storefront typically achieves:

  • Time to First Byte: under 200ms (vs. 800-1200ms traditional)
  • Largest Contentful Paint: under 1.5s (vs. 3-5s traditional)
  • Core Web Vitals: all green across mobile and desktop
  • API response times: under 100ms for cached queries

Deployment Architecture

Deploy the frontend independently from Magento using separate CI/CD pipelines. The frontend deploys in seconds via edge platforms, while Magento backend deployments follow the standard zero-downtime process with maintenance mode and cache warming.

For Magento 2 performance optimization and headless architecture consulting, our team brings deep experience across dozens of headless implementations for B2B and B2C merchants.

Need help with this?

Our team handles this kind of work daily. Let us take care of your infrastructure.