Skip to main content

01 - Headless Commerce: What it is, Advantages, Disadvantages and When It Really Makes Sense to Adopt It

Headless commerce separates the store customers see from the system managing catalogue and orders. What you gain, what you pay and how to decide if you need it.

What do you think about this article?

At a Glance

Headless commerce separates the store customers see from the system managing catalogue and orders. What you gain, what you pay and how to decide if you need it.

Headless Commerce 10 min

Headless commerce separates the store the customer sees from the system that manages catalogue, cart and orders. Here you see what you gain, what you pay and how to decide whether you need it.

headless commerce API-first commerce composable architecture MACH architecture frontend decoupled

What headless means, in one sentence and one example

Headless commerce means that the system that manages products, prices, carts, orders and payments does not produce web pages: it exposes data and operations through APIs, and any program (a website, an app, a kiosk in a shop) calls them to build its own interface. The “head” (the interface) is cut off from the “body” (the commercial logic), hence the name. If you have ever used a classic WooCommerce or Shopify theme, you have seen the opposite: the same system decides the price and draws the button.

An everyday example makes the idea concrete. A craft coffee roaster sells coffee on its own website and also wants an app for subscribers and a screen in the shop showing which blends are available. With a classic store it would have to maintain three copies of the catalogue, or force the app into a web page. With a headless backend the catalogue stays one, and the three interfaces read it with the same request. The gain is the freedom to design each channel; the cost, as you will see, is that you now build the three interfaces yourself.

In practice a headless architecture has three parts: the commerce backend, which owns the data and the rules (what a product costs, whether it is available, how shipping is calculated); one or more frontends, which contain no business rules, only presentation; and possibly a gateway that acts as a single entrance for authentication and request limits. The rule that holds the design together is that the price of an item is decided once, in the backend, and no frontend recalculates it on its own.

What a real call looks like: Shopify’s Storefront API

To make this concrete we use the Shopify Storefront API, which is GraphQL: a single address, and in the request you describe exactly the fields you need. The listing below reads the catalogue in pages of two products. For each product the query asks for the identifier, the title, the handle (the URL part) and the minimum price among the variants, plus pageInfo, which says whether a next page exists and from which cursor to restart. The fetchAll loop continues until hasNextPage is false: it is the standard way to walk a GraphQL collection, because a real catalogue is read in pages, not in a single response.

export const PRODUCTS_QUERY = `
  query Products($first: Int!, $after: String) {
    products(first: $first, after: $after) {
      pageInfo { hasNextPage endCursor }
      nodes {
        id
        title
        handle
        priceRange { minVariantPrice { amount currencyCode } }
      }
    }
  }
`;

export type Product = {
  id: string;
  title: string;
  handle: string;
  priceRange: { minVariantPrice: { amount: string; currencyCode: string } };
};

type Page = { pageInfo: { hasNextPage: boolean; endCursor: string | null }; nodes: Product[] };

export async function fetchPage(endpoint: string, token: string, after?: string): Promise<Page> {
  const res = await fetch(endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      // PRIVATE token: this code runs on the server, never in the browser
      'Shopify-Storefront-Private-Token': token,
    },
    body: JSON.stringify({ query: PRODUCTS_QUERY, variables: { first: 2, after } }),
  });
  if (!res.ok) throw new Error(`Storefront API: HTTP ${res.status}`);
  const body = await res.json();
  // GraphQL answers 200 even when the query is wrong: errors are in the body
  if (body.errors) throw new Error(body.errors.map((e: { message: string }) => e.message).join('; '));
  return body.data.products;
}

export async function fetchAll(endpoint: string, token: string): Promise<Product[]> {
  const all: Product[] = [];
  let after: string | undefined;
  for (;;) {
    const page = await fetchPage(endpoint, token, after);
    all.push(...page.nodes);
    if (!page.pageInfo.hasNextPage) return all;
    after = page.pageInfo.endCursor ?? undefined;
  }
}

// Output:
// HTTP requests: 2
// moka-3 -> 24.0 EUR
// macinacaffe -> 39.0 EUR
// filtro-v60 -> 12.5 EUR
// wrong token: Storefront API: HTTP 401

Two lines matter more than the others. The first is the Shopify-Storefront-Private-Token header: the documentation distinguishes a public token, meant for browsers and apps where it is visible to customers, from a private token, to be used only from a server. This code runs on the server, so it uses the private one; if you sent it to the browser, anyone opening the developer tools could copy it. The second is the check on body.errors: a GraphQL server can answer with status 200 even when the query has an error, and without that check the program would carry on with an empty data without warning anyone.

The output shown above does not come from a Shopify store: it was obtained by running the same file with Node 24 against a small local server that imitates the shape of the response, with three products and pages of two (the two HTTP requests are the two pages). It therefore proves nothing about Shopify’s behaviour, and the token is not valid for a real store: it is a test of the pagination loop and of the handling of the 401 error. API versions are dated and quarterly: in the address I put 2026-10, the most recent stable version, consulted on 2026-11-12 on the versioning page, which guarantees each stable version for at least twelve months. This means that sooner or later you have to update the number and reread the release notes.

What you really gain

There are four advantages and they need to be kept distinct, because only some of them apply to you.

  • Freedom on the frontend: you can choose React, Vue, Angular, Svelte or a native app, and test the interface like any other software.
  • One backend, several channels: website, app, point of sale and B2B integrations read the same catalogue and write to the same order system.
  • Separate scalability: static pages on a CDN withstand traffic independently of the backend, which works mostly on carts and payments.
  • Controllable performance: you decide what to pre-generate, what to cache and how many images to load.

The first and the last are two faces of the same thing: control over what the browser receives. It matters only if you have someone who can exploit it, because a badly written frontend on a headless backend is slower than a good theme. The second holds only if the channels really exist: three hypothetical channels do not justify the cost. On performance the reference threshold is the one from web.dev: a good Largest Contentful Paint is 2.5 seconds or less, measured at the 75th percentile of real page loads. There is no conversion rate guaranteed by moving to headless: the figures circulating in industry reports are partisan and I do not report them here, because no primary source supports them in general terms. Measure the LCP of your current store first: if it is already under the threshold, the gain will be small. How to measure it in the field and how to bring it under the threshold is in the article on Core Web Vitals and SEO.

What you pay: the costs guides leave out

The main cost is that everything the classic theme did on its own you now write yourself: the persistent cart, the checkout page, transactional emails, structured data for search engines, cookie handling, content preview (if you hand it to a CMS, see the article on content commerce). I do not have a reliable figure for the ratio between the cost of a headless project and that of a theme, and I prefer not to invent one: the ratio depends on how much you customise and on who does the work. I can, however, tell you where the expense accumulates.

  • More systems, more points of failure: frontend, commerce backend, any CMS and search services have to be released and monitored separately.
  • Skills: you need someone who knows the chosen framework and its rendering rules well, not just someone who can configure a theme.
  • Built-in features that disappear: abandoned-cart emails, loyalty programmes and chat often lived in the monolith’s plugins and have to be reintegrated.
  • Version upgrades: the backend API changes over time (as seen, Shopify releases a version every quarter) and the frontend has to follow it.

If you have to remember only one, remember the third: it is the one discovered late. Before the project, list all the functions the current store performs without anyone noticing, and for each one write down who will provide it afterwards. The time it takes is a fraction of the time needed to discover halfway through the work that abandoned-cart recovery is gone.

How to decide: three questions instead of numeric thresholds

Many guides give thresholds such as “at least three developers” or “turnover above a million”. They are the writer’s judgements, not research results, and they change from one sector to another. I prefer three questions you can answer yourself, with your own store’s data.

QuestionIf the answer is yesIf the answer is no
Does a limit of the current theme cost you sales or time, and can you prove it (measured LCP, impossible feature)?Headless can solve itOptimise the theme before changing architecture
Do you have, or can you hire, someone who will maintain a modern frontend for years?The project stands upYou risk a site nobody knows how to update
Do you serve more than one channel with the same commercial logic?The shared backend pays for itselfYou do not need the omnichannel advantage yet

Three “yes” answers indicate that the investment has a reason; two “no” out of three, that you are still searching for your product and a managed store, where changing a price costs one click, suits you better. The middle road is the most underrated: you can keep the theme for the website and use the APIs only for a new channel, such as the app, or replace the frontend and leave the backend as it is. You migrate step by step, and the step-by-step migration pattern is the Strangler Fig described by Martin Fowler, which we will take up in the article on MACH architecture.

The platforms you will meet in the series

Platforms fall into two families, and the difference that matters to you is who runs the servers. With managed services (SaaS) you pay a fee and the vendor maintains the infrastructure: Shopify, with the Storefront API seen above, and commercetools, aimed at large enterprises. With open-source platforms you install and operate the software yourself: Medusa (Node.js and TypeScript, modular) and Saleor (Python and Django, with GraphQL as the main interface). In the middle is WooCommerce, which has a REST API but was born as a store with the theme included, so using it headless is possible but not natural. You will find the details in the dedicated chapters: Shopify Hydrogen, Medusa and Saleor.

The choice between the two families is a trade-off between time and control: the managed service takes the infrastructure off your hands and ties you to its pricing model and its limits, open source gives you the code and hands you updates, backups and security. There is no best choice in absolute terms; there is the one consistent with the team you have.

What you can do now

You can explain what it means to separate the interface from the commerce backend, read a GraphQL call to a catalogue with cursor pagination, tell a public token from a private one and recognise the costs that the separation brings with it. Above all you have three questions to decide with your store’s data instead of industry reports. In the next article we will see how these ideas are organised into a complete architecture.

Sources

Next in the series MACH Commerce Architecture →

Try These Tools

Free developer tools related to this topic.

Commenti

Caricamento commenti...

Sign in to comment

Discuss this article in the community

Join the Telegram group to discuss with other developers, ask questions and share your experiences.

Did you like this article?

Explore other content on the blog or discover my projects