React Storefront auf Magento GraphQL aufbauen
AI generated
</>
{ }
React · Magento · GraphQL · Headless Commerce
React Storefront auf Magento GraphQL aufbauen
vom Schema bis zur fertigen Produktseite

Ein React Storefront auf Basis von Magentos GraphQL API entkoppelt Frontend und Backend vollständig und macht den Shop schneller, flexibler und leichter wartbar. Wer das Schema versteht, den richtigen Client wählt und Caching sowie Fehlerbehandlung von Anfang an mitdenkt, spart sich Monate an nachträglichem Refactoring.

22 Min. Lesezeit Magento GraphQL · Apollo Client · Headless Commerce React 19 · Magento 2.4.x

1. Warum ein React Storefront auf Magento GraphQL

Ein React Storefront auf Basis von Magentos GraphQL API ist die konsequente Weiterentwicklung des klassischen Luma Frontends. Statt server-gerenderter phtml-Templates liefert Magento nur noch Daten aus, und React übernimmt vollständig die Darstellung, das Routing und die Interaktivität im Browser. Dieser Ansatz entkoppelt die Release-Zyklen von Frontend und Backend, erlaubt eigene Deployment-Pipelines für den Storefront und öffnet die Tür für moderne Tools wie Vite, TanStack Query und Tailwind, die im Luma-Kontext nie sauber integrierbar waren.

Der zentrale Unterschied zu PWA Studio oder einem generischen Headless-Setup liegt darin, dass ein selbst gebauter React Storefront genau auf die Anforderungen eines konkreten Shops zugeschnitten wird. Kein ungenutzter Code, keine fremden Abhängigkeiten, keine Kompromisse bei der Bundle-Größe. Wer schon einmal versucht hat, ein PWA Studio Theme an ein individuelles Design-System anzupassen, kennt den Aufwand, unerwünschte Komponenten zu entfernen. Ein eigener React Storefront beginnt bei null und wächst nur um das, was tatsächlich gebraucht wird.

Technisch basiert jeder React Storefront auf Magento GraphQL auf drei Säulen: dem GraphQL Schema als Vertrag zwischen Backend und Frontend, einem Client wie Apollo oder urql für Caching und Request-Management, und einer sauberen Trennung zwischen Server- und Client-State. Die folgenden Abschnitte gehen jede dieser Säulen im Detail durch, mit lauffähigen Beispielen für Produktlisten, Produktdetailseiten und Authentifizierung.

2. Das Magento GraphQL Schema verstehen

Bevor die erste Zeile React-Code entsteht, lohnt sich ein gründlicher Blick in das Magento GraphQL Schema über die integrierte GraphiQL-Oberfläche unter /graphql. Das Schema folgt der Relay-Connection-Spezifikation für paginierte Listen: Felder wie products liefern nicht direkt ein Array, sondern eine Struktur mit items, page_info und total_count. Wer diese Konvention beim Aufbau des React Storefronts ignoriert, baut Pagination-Logik, die bei größeren Kategorien mit tausenden Produkten bricht.

Ein zweiter wichtiger Baustein ist die Unterscheidung zwischen ProductInterface und den konkreten Typen SimpleProduct, ConfigurableProduct und BundleProduct. GraphQL-Queries müssen mit Inline-Fragmenten (... on ConfigurableProduct) arbeiten, um typ-spezifische Felder wie configurable_options abzufragen. Für einen React Storefront, der mehrere Produkttypen im selben Katalog darstellt, ist dieses Muster unumgänglich und sollte früh in gemeinsam genutzten Fragment-Definitionen zentralisiert werden.


# GraphQL query fragment for a Magento product tile in a React storefront
fragment ProductTileFields on ProductInterface {
  uid
  name
  sku
  url_key
  small_image {
    url
    label
  }
  price_range {
    minimum_price {
      final_price { value currency }
      regular_price { value currency }
    }
  }
  ... on ConfigurableProduct {
    configurable_options {
      attribute_code
      label
      values { value_index label }
    }
  }
}

query CategoryProducts($categoryId: String!, $pageSize: Int!, $currentPage: Int!) {
  products(filter: { category_id: { eq: $categoryId } }, pageSize: $pageSize, currentPage: $currentPage) {
    total_count
    page_info { current_page page_size total_pages }
    items { ...ProductTileFields }
  }
}

Der Vorteil dieser Fragment-basierten Struktur zeigt sich beim Skalieren des React Storefronts: neue Seiten, die dieselben Produktkacheln darstellen, importieren einfach das bestehende Fragment, statt Felder erneut aufzulisten. Das reduziert Inkonsistenzen zwischen Kategorieseite, Suchergebnis und Cross-Selling-Widgets erheblich, weil alle drei exakt dieselben Felder anfragen und damit auch denselben Apollo-Cache-Eintrag teilen.

3. Apollo Client konfigurieren und einrichten

Für einen produktionsreifen React Storefront hat sich Apollo Client als GraphQL-Client durchgesetzt, weil er normalisiertes Caching, optimistische Updates und eine ausgereifte DevTools-Integration mitbringt. Die Alternative urql ist leichter und schneller eingerichtet, bietet aber ein weniger granulares Cache-Modell für komplexe Produktdaten mit verschachtelten Preisstrukturen, wie sie bei Bundle- und Konfigurationsprodukten in Magento auftreten.

Bei der Einrichtung des Apollo Clients für einen React Storefront ist die korrekte Konfiguration der InMemoryCache entscheidend. Magento GraphQL liefert für die meisten Entitäten eine uid, die als eindeutiger Cache-Key dient. Ohne explizite typePolicies normalisiert Apollo Produktdaten zwar automatisch über die id, aber Magento nutzt konsequent uid, weshalb eine eigene Key-Funktion nötig ist, damit Cache-Updates nach Mutationen wie dem Hinzufügen zum Warenkorb korrekt greifen.


// apolloClient.js — Apollo Client setup for a React storefront on Magento GraphQL
import { ApolloClient, InMemoryCache, createHttpLink, from } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { onError } from '@apollo/client/link/error';

const httpLink = createHttpLink({ uri: process.env.NEXT_PUBLIC_MAGENTO_GRAPHQL_URL });

// Attach store and customer context headers on every request
const authLink = setContext((_, { headers }) => {
  const token = typeof window !== 'undefined' ? localStorage.getItem('customerToken') : null;
  return {
    headers: {
      ...headers,
      Store: process.env.NEXT_PUBLIC_MAGENTO_STORE_CODE,
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
    },
  };
});

const errorLink = onError(({ graphQLErrors, networkError }) => {
  graphQLErrors?.forEach((err) => console.error('[GraphQL error]', err.message, err.extensions));
  if (networkError) console.error('[Network error]', networkError);
});

export const apolloClient = new ApolloClient({
  link: from([errorLink, authLink, httpLink]),
  cache: new InMemoryCache({
    typePolicies: {
      ProductInterface: { keyFields: ['uid'] },
      ConfigurableProduct: { keyFields: ['uid'] },
      Cart: { keyFields: ['id'] },
    },
  }),
});

Ein Detail, das in vielen React Storefront Projekten unterschätzt wird, ist der Store-Header. Magento nutzt ihn, um in Multi-Store-Setups die richtige Store-View und damit Preise, Sprache und Verfügbarkeit zu bestimmen. Fehlt der Header, greift die Default-Store-View, was in internationalen Shops zu falschen Preisen oder fehlenden Übersetzungen führt, ein Fehler, der oft erst im Staging bei einem zweiten Store auffällt.

4. Produktlisten, Facetten und Pagination laden

Kategorieseiten sind der Bereich, in dem ein React Storefront seine Performance-Vorteile gegenüber Luma am deutlichsten zeigt. Statt eines vollständigen Seiten-Reloads bei jedem Filter-Klick aktualisiert React nur die betroffenen Komponenten, während Apollo Client die Anfrage im Hintergrund abfeuert und das Ergebnis normalisiert cached. Die aggregations im GraphQL-Response liefern die Facetten-Daten (Größe, Farbe, Preis-Range) inklusive der jeweiligen Trefferzahl pro Option, was clientseitig direkt für Filter-Badges genutzt werden kann.

Für die Pagination empfiehlt sich in einem React Storefront das Cursor-ähnliche Muster mit currentPage und pageSize, kombiniert mit der Apollo fetchMore-Funktion für Infinite-Scroll-Varianten oder klassischer Seitennavigation. Wichtig ist, den Filter-State in der URL zu spiegeln, damit gefilterte Kategorieseiten teilbar und für Suchmaschinen crawlbar bleiben, ein Punkt, der bei rein clientseitigem State schnell übersehen wird.


// CategoryProductGrid.jsx — filterable product grid for a React storefront
import { useQuery } from '@apollo/client';
import { useSearchParams } from 'next/navigation';
import { CATEGORY_PRODUCTS_QUERY } from './queries';

export function CategoryProductGrid({ categoryId }) {
  const searchParams = useSearchParams();
  const page = Number(searchParams.get('p') ?? '1');
  const priceFilter = searchParams.get('price');

  const { data, loading, fetchMore } = useQuery(CATEGORY_PRODUCTS_QUERY, {
    variables: {
      categoryId,
      pageSize: 24,
      currentPage: page,
      filter: priceFilter ? { price: { from: priceFilter.split('-')[0], to: priceFilter.split('-')[1] } } : {},
    },
    notifyOnNetworkStatusChange: true,
  });

  if (loading && !data) return <ProductGridSkeleton count={24} />;

  const { items, total_count, page_info } = data.products;

  return (
    <>
      <FacetSidebar aggregations={data.products.aggregations} />
      <ProductTiles items={items} />
      <Pagination current={page_info.current_page} total={page_info.total_pages} totalCount={total_count} />
    </>
  );
}

5. Produktdetailseite mit konfigurierbaren Produkten

Die Produktdetailseite ist der komplexeste Einzelbaustein jedes React Storefronts, weil konfigurierbare Produkte mehrdimensionale Varianten-Logik erfordern. Magento GraphQL liefert über configurable_options die verfügbaren Attribute (etwa Größe und Farbe) mit allen möglichen Werten, aber nicht direkt, welche Kombinationen tatsächlich lagernd sind. Diese Information steckt in variants, einem Array aus konkreten Produkt-Varianten mit ihrer jeweiligen Attribut-Kombination und SKU.

Ein robustes Auswahl-Pattern für den React Storefront baut aus variants eine Lookup-Tabelle, die anhand der gewählten Attribut-Werte in Sekundenbruchteilen die passende Variante findet, inklusive Lagerbestand und variantenspezifischem Bild. Ohne diese Vorverarbeitung müsste bei jedem Klick auf eine Farboption eine neue GraphQL-Anfrage gestellt werden, was sich spürbar unruhig anfühlt und unnötige Serverlast erzeugt.


// useConfigurableSelection.js — variant lookup for React storefront PDPs
import { useMemo, useState } from 'react';

export function useConfigurableSelection(configurableProduct) {
  const [selected, setSelected] = useState({});

  // Build a lookup map: "64_red" -> variant
  const variantMap = useMemo(() => {
    const map = new Map();
    configurableProduct.variants.forEach((variant) => {
      const key = variant.attributes
        .map((a) => `${a.code}_${a.value_index}`)
        .sort()
        .join('|');
      map.set(key, variant);
    });
    return map;
  }, [configurableProduct.variants]);

  const activeVariant = useMemo(() => {
    const key = Object.entries(selected)
      .map(([code, value]) => `${code}_${value}`)
      .sort()
      .join('|');
    return variantMap.get(key) ?? null;
  }, [selected, variantMap]);

  const selectOption = (code, valueIndex) =>
    setSelected((prev) => ({ ...prev, [code]: valueIndex }));

  return { selected, selectOption, activeVariant, inStock: activeVariant?.product.stock_status === 'IN_STOCK' };
}

6. Customer Token und Session-Handling

Authentifizierung ist einer der Bereiche, in denen ein selbst gebauter React Storefront deutlich mehr Sorgfalt erfordert als ein Server-Rendering-Ansatz. Magento GraphQL nutzt Bearer-Token-Authentifizierung über die Mutation generateCustomerToken, die einen Token mit begrenzter Gültigkeit zurückgibt. Dieser Token muss sicher gespeichert werden, wobei localStorage zwar praktisch, aber anfällig für XSS ist, während HttpOnly-Cookies über eine eigene Backend-for-Frontend-Schicht mehr Schutz bieten, aber zusätzliche Infrastruktur benötigen.

Für Gäste-Checkouts arbeitet ein React Storefront zusätzlich mit einem cart_id, der unabhängig vom Customer-Token existiert und in einem Cookie oder localStorage persistiert wird. Der entscheidende Punkt beim Übergang von Gast zu eingeloggtem Kunden ist die Mutation mergeCarts, die den anonymen Warenkorb mit dem des Kunden zusammenführt, ein Schritt, der in vielen Implementierungen vergessen wird und zu verlorenen Warenkörben nach dem Login führt.

7. Caching-Strategie für den React Storefront

Caching entscheidet maßgeblich über die gefühlte Geschwindigkeit eines React Storefronts. Statische Daten wie Store-Konfiguration, Kategoriebaum und CMS-Blöcke ändern sich selten und eignen sich hervorragend für serverseitiges Caching mit langer Time-to-live, kombiniert mit einer expliziten Invalidierung über Magentos Cache-Tags, sofern die Deployment-Plattform Incremental Static Regeneration unterstützt. Produktpreise und Lagerbestände hingegen sind volatiler und sollten client-seitig mit kurzer Apollo-Cache-Time-to-live oder network-only Fetch-Policy behandelt werden.

Ein bewährtes Muster für den React Storefront ist die Kombination aus cache-first für Navigationsdaten und cache-and-network für Produktlisten: der Nutzer sieht sofort den zwischengespeicherten Stand, während im Hintergrund aktualisierte Preise und Verfügbarkeiten nachgeladen werden. Das vermeidet sichtbares Laden bei wiederholten Besuchen derselben Kategorie, ohne veraltete Preise anzuzeigen, sobald die frische Antwort eintrifft.

8. Fehlerbehandlung bei Magento GraphQL Antworten

Magento GraphQL gibt Fehler auf zwei Ebenen zurück: als HTTP-Statuscode für Transport-Probleme und als errors-Array innerhalb einer HTTP-200-Antwort für fachliche Fehler wie ungültige SKUs oder abgelaufene Carts. Ein React Storefront, der nur auf HTTP-Status prüft, übersieht diese fachlichen Fehler komplett, weil GraphQL selbst bei einem teilweise fehlgeschlagenen Query mit Status 200 antwortet.

Jeder Magento GraphQL Error trägt in extensions.category eine Kategorie wie graphql-no-such-entity oder graphql-authorization, die sich für gezielte Fehlerbehandlung im React Storefront nutzen lässt: abgelaufene Tokens lösen einen automatischen Re-Login-Flow aus, fehlende Entitäten zeigen eine 404-Seite, und Validierungsfehler werden direkt am betroffenen Formularfeld angezeigt, statt einer generischen Fehlermeldung am Seitenrand.


// errorCategoryHandler.js — routing Magento GraphQL errors by category in a React storefront
export function handleGraphQlError(error, { onAuthExpired, onNotFound, onValidation }) {
  const category = error.extensions?.category;

  switch (category) {
    case 'graphql-authorization':
      return onAuthExpired();
    case 'graphql-no-such-entity':
      return onNotFound();
    case 'graphql-input':
      return onValidation(error.message);
    default:
      console.error('[Unhandled GraphQL error]', error.message, category);
  }
}

9. React Storefront Ansätze im Vergleich

Es gibt mehrere Wege, wie GraphQL-Daten in einem React Storefront verarbeitet werden können. Die Wahl beeinflusst Caching-Verhalten, Bundle-Größe und Entwicklungsgeschwindigkeit erheblich.

Ansatz Caching Bundle-Größe Empfehlung
Apollo Client Normalisiert, granular ~35 KB gzip Komplexe Kataloge, viele Mutationen
urql Document-Cache ~9 KB gzip Kleinere Storefronts, einfache Queries
fetch + TanStack Query Query-Key-basiert ~13 KB gzip Team kennt REST-Patterns bereits
PWA Studio (Peregrine) Vorgegeben, wenig anpassbar Groß, viel Overhead Nur bei sehr engem Zeitrahmen

Für die meisten mittelgroßen bis großen Kataloge ist Apollo Client die tragfähigste Basis für einen React Storefront, weil normalisiertes Caching bei Warenkorb-Mutationen automatisch konsistente UI-Updates über mehrere Komponenten hinweg erzeugt, ohne manuelles Re-Fetching. Kleinere Projekte mit überschaubarem Query-Umfang fahren mit urql oft schneller, weil die Einstiegshürde niedriger ist und weniger Konfigurationsaufwand entsteht.

Mironsoft

React Storefronts auf Magento GraphQL, von der Architektur bis zum Deployment

Ein eigener React Storefront für euren Magento Shop?

Wir bauen React Storefronts auf Basis von Magento GraphQL, mit Apollo Client, sauberem Caching und robuster Fehlerbehandlung, maßgeschneidert auf euren Katalog und euer Design.

Architektur-Beratung

Schema-Analyse, Client-Auswahl und Datenmodell für euren Storefront

Implementierung

Produktseiten, Warenkorb und Checkout mit Magento GraphQL umsetzen

Performance-Tuning

Caching-Strategie, Bundle-Analyse und Core Web Vitals optimieren

10. Zusammenfassung

Ein React Storefront auf Magento GraphQL steht auf drei Säulen: einem gut verstandenen Schema mit Fragmenten für Wiederverwendbarkeit, einem Client wie Apollo, der normalisiertes Caching und Mutationen sauber verwaltet, und einer expliziten Strategie für Authentifizierung, Caching und Fehlerbehandlung. Wer diese drei Bereiche von Anfang an durchdenkt, vermeidet die typischen Stolpersteine bei Konfigurationsprodukten, Multi-Store-Setups und Gast-zu-Kunde-Übergängen.

Der größte Vorteil gegenüber PWA Studio liegt in der vollständigen Kontrolle über Bundle-Größe und Abhängigkeiten. Ein React Storefront, der nur die tatsächlich benötigten GraphQL-Felder abfragt und nur die wirklich genutzten Komponenten bündelt, lädt spürbar schneller als ein generisches Headless-Framework mit ungenutztem Overhead. Diese Kontrolle zahlt sich langfristig in besseren Core Web Vitals und niedrigeren Absprungraten aus.

React Storefront auf Magento GraphQL — Das Wichtigste auf einen Blick

Schema

Relay-Connections für Listen, Inline-Fragmente für Produkttypen. Fragment-Definitionen zentralisieren, um Konsistenz zu sichern.

Client

Apollo Client mit keyFields: ['uid'] für korrektes Cache-Update nach Warenkorb-Mutationen.

Auth & Cart

Bearer-Token für Kunden, cart_id für Gäste, mergeCarts beim Login nicht vergessen.

Fehlerbehandlung

extensions.category im GraphQL-Error auswerten, nicht nur HTTP-Status prüfen.

11. FAQ: React Storefront auf Magento GraphQL

1Was ist ein React Storefront auf Magento GraphQL?
Ein eigenständiges Frontend, komplett entkoppelt vom Magento-Backend, das Produktdaten, Warenkorb und Checkout ausschließlich über GraphQL abruft.
2Warum Apollo Client statt direktem fetch?
Normalisiertes Caching über die uid und automatische UI-Updates nach Mutationen, ohne manuelles erneutes Laden.
3Wie werden konfigurierbare Produkte abgebildet?
Über configurable_options für Attribute und variants für lagernde Kombinationen. Eine Lookup-Tabelle findet die passende Variante ohne Zusatzanfrage.
4Wie funktioniert Authentifizierung?
generateCustomerToken liefert einen Bearer-Token. Gast-Warenkörbe nutzen cart_id und werden per mergeCarts beim Login zusammengeführt.
5Warum ist der Store-Header wichtig?
Er bestimmt Preise, Sprache und Verfügbarkeit der Store-View. Ohne ihn greift die Default-Store-View mit falschen Daten in Multi-Store-Setups.
6Wie werden GraphQL-Fehler erkannt?
Über das errors-Array und extensions.category in der Antwort, auch wenn der HTTP-Status 200 ist. Der HTTP-Status allein reicht nicht aus.
7Welche Caching-Strategie für Produktlisten?
cache-and-network zeigt sofort gecachte Daten und aktualisiert im Hintergrund. Statische Inhalte vertragen längere Cache-Zeiten als Preise.
8Apollo Client oder urql?
Apollo für komplexe Kataloge mit vielen Mutationen, urql für kleinere Storefronts mit einfacheren Anforderungen und geringerem Konfigurationsaufwand.
9Wie werden Facetten genutzt?
Das Feld aggregations liefert Facetten mit Trefferzahlen. Filter-State sollte in der URL gespiegelt werden für Teilbarkeit und Crawlbarkeit.
10Lohnt sich ein eigener Storefront gegenüber PWA Studio?
Bei individuellen Anforderungen ja, wegen voller Kontrolle über Bundle-Größe. PWA Studio passt eher bei sehr engem Zeitrahmen und Standardfällen.