News

Shopify Oxygen Architektur Best Practices: Hydrogen, GraphQL & Deployment sauber aufsetzen

Von Erol Demirkoparan
8 min
Shopify Oxygen Architektur Best Practices: Hydrogen, GraphQL & Deployment sauber aufsetzen - Cloudox Software Agentur Blog

1) Zielbild: Saubere Trennung von Hydrogen (Oxygen) und Shopify Themes

Eine robuste Shopify Oxygen-Architektur trennt konsequent:

  • Storefront (Headless): Shopify Hydrogen App läuft auf Oxygen Deployment (Edge Runtime, schnell, global).
  • Commerce-Backend: Shopify (Admin/Storefront APIs), Daten via GraphQL API.
  • Theme-Layer: Shopify Themes mit Liquid Templating für Inhalte/Pages, die (noch) nicht headless migriert sind oder bewusst im Theme bleiben.

Best Practice: Lege Integrationsgrenzen fest (welche Routen laufen in Hydrogen vs. Theme), um Doppelpflege und SEO-Risiken zu vermeiden (Canonical, Redirects, Sitemap-Ownership).

FeatureDetails
Rendering-StrategieHydrogen: SSR/Streaming an der Edge (Oxygen). Theme: Liquid server-rendered im Shopify-Stack.
DatenzugriffHydrogen: Storefront GraphQL API. Theme: Liquid-Objekte + optional App Proxies / Sections.
CachingEdge-Caching & stale-while-revalidate in Hydrogen; Theme-Caching indirekt über Shopify/CDN.
SEO-KontrolleHydrogen: volle Kontrolle (Meta/Structured Data/Headers). Theme: Shopify-Standards + Liquid-Anpassungen.
DeploymentsHydrogen via Oxygen Deployment Pipeline. Themes via theme publish (Shopify CLI) getrennt versionieren.

2) GraphQL API Best Practices (Storefront): Query-Design, Fehlerbild, Performance

2.1 Query-Design: Nur das abfragen, was du renderst

Die GraphQL API ist ideal für Headless, weil du die Response exakt auf deine UI zuschneiden kannst. Best Practices:

  • Fragmentierung: Wiederverwendbare Fragments für ProductCard, Money, Image.
  • Pagination: Vermeide große Lists; nutze first/after und baue UI für Load More.
  • Fehler-Toleranz: Unterscheide Transport-Fehler (HTTP) vs. GraphQL Errors (Partial Data möglich).
  • Stabilität: Typisiere Queries (Codegen) und versioniere API-Änderungen.

2.2 TypeScript API Integration (Hydrogen + Storefront GraphQL)

Unten ein realistisches Muster für eine Hydrogen-Integration: typed Fetch-Client, GraphQL-Query, Fehlerbehandlung und Cache-Header-Strategie für Edge.

TypeScript: Storefront GraphQL Client + Product Query

type GraphQLErrorItem = {
  message: string;
  extensions?: Record<string, unknown>;
};

type GraphQLResponse<T> = {
  data?: T;
  errors?: GraphQLErrorItem[];
};

type MoneyV2 = {
  amount: string;
  currencyCode: string;
};

type Image = {
  url: string;
  altText?: string | null;
  width?: number | null;
  height?: number | null;
};

type Product = {
  id: string;
  handle: string;
  title: string;
  description: string;
  featuredImage?: Image | null;
  priceRange: {
    minVariantPrice: MoneyV2;
  };
};

type ProductByHandleData = {
  productByHandle: Product | null;
};

const PRODUCT_BY_HANDLE_QUERY = `#graphql
  query ProductByHandle($handle: String!) {
    productByHandle(handle: $handle) {
      id
      handle
      title
      description
      featuredImage {
        url
        altText
        width
        height
      }
      priceRange {
        minVariantPrice {
          amount
          currencyCode
        }
      }
    }
  }
`;

type StorefrontClientOptions = {
  storeDomain: string;
  storefrontAccessToken: string;
  apiVersion: string;
};

export class StorefrontGraphQLClient {
  private endpoint: string;
  private token: string;

  constructor(private opts: StorefrontClientOptions) {
    this.endpoint = `https://${opts.storeDomain}/api/${opts.apiVersion}/graphql.json`;
    this.token = opts.storefrontAccessToken;
  }

  async request<T>(query: string, variables?: Record<string, unknown>): Promise<T> {
    const res = await fetch(this.endpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Shopify-Storefront-Access-Token': this.token,
      },
      body: JSON.stringify({ query, variables }),
    });

    if (!res.ok) {
      const text = await res.text();
      throw new Error(`Storefront API HTTP ${res.status}: ${text}`);
    }

    const payload = (await res.json()) as GraphQLResponse<T>;

    if (payload.errors?.length) {
      // GraphQL kann data + errors liefern; je nach Use Case entscheiden
      const messages = payload.errors.map((e) => e.message).join('; ');
      throw new Error(`Storefront GraphQL errors: ${messages}`);
    }

    if (!payload.data) {
      throw new Error('Storefront GraphQL response missing data');
    }

    return payload.data;
  }
}

export async function getProductByHandle(handle: string) {
  const client = new StorefrontGraphQLClient({
    storeDomain: process.env.SHOPIFY_STORE_DOMAIN as string,
    storefrontAccessToken: process.env.SHOPIFY_STOREFRONT_TOKEN as string,
    apiVersion: '2025-01',
  });

  const data = await client.request<ProductByHandleData>(PRODUCT_BY_HANDLE_QUERY, { handle });

  if (!data.productByHandle) {
    return { status: 404 as const, product: null };
  }

  return { status: 200 as const, product: data.productByHandle };
}

Oxygen-spezifisch: In Hydrogen/Oxygen arbeitest du typischerweise mit Edge-Caching (z. B. kurze TTL + SWR). Plane das Query-Design so, dass du Cache-Hit-Rates erhöhst (stabile Query-Keys, konsistente Variablen, getrennte Queries für personalisierte Inhalte).

3) Liquid Templating: Wann Themes sinnvoll sind (und wie du sauber integrierst)

Liquid Templating ist die Template-Sprache von Shopify Themes. Sie rendert serverseitig im Shopify-Theme-Stack und hat direkten Zugriff auf Theme-Objekte (z. B. product, collection, cart) abhängig vom Template-Kontext.

3.1 Best Practices für Liquid in hybriden Architekturen

  • Klare Ownership pro URL: Eine Route gehört entweder dem Theme oder Hydrogen (nicht beides). Für Migrationen setze 301-Redirects.
  • Composable Sections: Nutze Sections/Blocks für Marketing-Seiten, die schnell iterieren müssen.
  • App Proxy / Headless Widgets: Wenn Hydrogen Daten/HTML liefern soll, kapsle es über stabile Endpunkte und integriere im Theme gezielt (nicht als „Spaghetti“).
  • SEO/Structured Data: Vermeide doppelte JSON-LD-Ausgaben (Theme + Hydrogen). Definiere eine Quelle.

3.2 Typische Liquid-Fallstricke

  • Zu viel Logik im Template: Liquid ist bewusst eingeschränkt; komplexe Logik gehört in Apps/Services.
  • Performance: Viele include/snippet-Aufrufe und große Loops können Theme-Rendering verlangsamen.
  • Unklare Datenquelle: Wenn Produktdaten sowohl via GraphQL in Hydrogen als auch via Liquid gerendert werden, entstehen Inkonsistenzen (Preis, Verfügbarkeit, Metafields).

4) Oxygen Deployment: Branching, Environments, Rollbacks

Oxygen Deployment sollte wie ein modernes Web-Produkt betrieben werden: reproduzierbar, getestet, mit klaren Umgebungen. Best Practices:

  • Preview Deployments pro PR: Stakeholder können Features prüfen, ohne Produktion zu riskieren.
  • Environment Variables: Tokens/Keys ausschließlich als Secrets; nie ins Repo.
  • Rollback-Strategie: Versionierte Releases; im Fehlerfall auf vorheriges Deployment zurück.
  • Observability: Error-Tracking + Performance-Metriken (TTFB, Cache Hit Rate, GraphQL Latency).

5) YAML Deployment Script: CI für Hydrogen auf Oxygen

Ein CI-Workflow sollte: Dependencies installieren, TypeScript builden, Tests ausführen und anschließend deployen. Das folgende Beispiel zeigt eine typische Pipeline-Struktur, die du an deine Oxygen/Shopify-Hydrogen-Deploy-Mechanik anpasst (z. B. via Shopify CLI und passende Tokens).

YAML: CI Pipeline für Build & Oxygen Deployment

name: hydrogen-oxygen-deploy

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    permissions:
      contents: read

    env:
      SHOPIFY_STORE_DOMAIN: ${{ secrets.SHOPIFY_STORE_DOMAIN }}
      SHOPIFY_STOREFRONT_TOKEN: ${{ secrets.SHOPIFY_STOREFRONT_TOKEN }}
      OXYGEN_DEPLOY_TOKEN: ${{ secrets.OXYGEN_DEPLOY_TOKEN }}

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Typecheck
        run: npm run typecheck

      - name: Unit tests
        run: npm test

      - name: Build
        run: npm run build

      - name: Deploy to Oxygen (main only)
        if: github.ref == 'refs/heads/main'
        run: |
          npm run deploy:oxygen
        env:
          OXYGEN_DEPLOY_TOKEN: ${{ secrets.OXYGEN_DEPLOY_TOKEN }}

6) Architektur-Blueprint (Hydrogen + Theme + APIs)

flowchart LR
  U[User] --> CDN[Edge/CDN]
  CDN --> OX[Shopify Hydrogen on Oxygen]
  CDN --> TH[Shopify Themes (Liquid)]

  OX -->|GraphQL API| SF[Storefront API]
  OX -->|optional GraphQL/REST| ADM[Admin API]
  TH -->|Liquid objects & theme render| SHP[Shopify Core]

  SF --> SHP
  ADM --> SHP

7) Konkrete Checkliste zur Verbesserung deiner Shopify-Architektur

  • Routen-Matrix: Liste alle URLs und entscheide „Hydrogen“ vs. „Theme“ inkl. Redirect-Plan.
  • GraphQL Query Audit: Entferne Felder, die nicht gerendert werden; füge Pagination/Fragments hinzu.
  • Caching-Policy: Definiere TTL/SWR pro Seitentyp (PDP, PLP, CMS, Cart).
  • Fehlerbild: Standardisiere Error-Handling (404 vs. 500), Logging-Korrelation pro Request.
  • Deployment Hygiene: Preview deploys, Secrets, Rollbacks, Monitoring.
  • Theme Governance: Liquid nur für das, was bewusst im Theme bleibt; keine „halb-headless“ Doppelquellen.

8) Wann du eine externe Umsetzung brauchst

Wenn du die Trennung von Shopify Hydrogen, Shopify Themes und Oxygen Deployment sauber aufsetzen willst (inkl. Query-Design, Caching und CI), lohnt sich ein Setup-Workshop mit klaren Deliverables (Routenplan, Datenmodell, Deployment-Blueprint). Mehr dazu auf der Seite Shopify Agentur.

Häufig gestellte Fragen

Autor

Erol Demirkoparan

Erol Demirkoparan

Senior Software Architect

Full-Stack & Cloud-Native Systems Expert. Spezialisiert auf AWS, Next.js und skalierbare SaaS-Architekturen. Building the future of automated SEO.

AWSNext.jsScalable SaaSSystem Architecture

Veröffentlicht am

8. Januar 2026

Das könnte Sie auch interessieren