So migrieren Sie Shopify Scripts zu Functions: Das vollständige Code-Tutorial (Ausgabe 2026)

So migrieren Sie Shopify Scripts zu Functions: Das vollständige Code-Tutorial (Ausgabe 2026)

So migrieren Sie Shopify Scripts zu Functions: Das vollständige Code-Tutorial (Ausgabe 2026)

So migrieren Sie Shopify Scripts zu Functions — Blog-Heldenillustration

Es ist der 16. April 2026. Gestern — der 15. April — hat Shopify den Script Editor endgültig gesperrt. Du kannst kein neues Script mehr erstellen oder veröffentlichen. Die Abschaltung der Ausführung erfolgt in 75 Tagen, am 30. Juni 2026.

Wenn du ein Shopify-Plus-Entwickler bist — oder die Agentur, die einen Plus-Store betreut — und diese Migration seit zwölf Monaten auf den „nächsten Sprint“ verschoben hast, hast du ein Problem. Kein „kann man später beheben“-Problem. Ein „dein Checkout bricht am 1. Juli um Mitternacht zusammen“-Problem. Die meisten Plus-Stores haben im Laufe der Jahre 5 bis 20 Scripts angesammelt, von denen jedes unauffällig eine Rabattregel, ein Ausblenden von Versandarten oder eine Zahlungssperre antreibt, an die sich niemand mehr erinnert.

Dieser Leitfaden ist das technische Migrationshandbuch, von dem wir uns im Januar gewünscht hätten, dass es existiert. Er deckt den eigentlichen Code ab — nicht nur die Strategie. Bis du fertig gelesen hast, weißt du, wie du mit der Shopify CLI eine Function scaffoldest, die Rust- oder JavaScript-Logik für Rabatte, Versandanpassungen und Zahlungsanpassungen schreibst, sie sicher gegen eine markierte Teilmenge deiner Kunden testest und sie produktiv ausrollst, ohne deinen bestehenden Checkout zu beschädigen.

Hol die Scripts aus deinem Store heraus und die Functions hinein.


Developer migrating Shopify Scripts to Shopify Functions modules

Kurzantwort: Scripts → Functions in 60 Sekunden

Die Migration in einem Absatz: Shopify Scripts (Ruby-Code im Script Editor, nur für Plus) werden durch Shopify Functions ersetzt (WebAssembly-Module, geschrieben in Rust oder JavaScript, für alle Pläne verfügbar). Du scaffoldest eine Function mit shopify app generate extension, schreibst eine run.graphql-Abfrage, die die benötigten Warenkorbdaten abruft, schreibst eine run.rs- oder run.js-Datei, die Operationen zurückgibt (Rabatte, ausgeblendete Versandarten usw.), deployest dann mit shopify app deploy und aktivierst sie über den Admin oder eine GraphQL-Mutation. Functions laufen als kompiliertes WASM mit unter 5 ms Latenz, funktionieren in jedem Plan und sind der einzige Anpassungsweg, den Shopify künftig unterstützt.

Was sich am 30. Juni tatsächlich ändert

Bevor wir irgendeinen Code anfassen, sollten wir die Daten richtig einordnen. Es gibt zwei davon, und beide sind wichtig.

Datum

Was passiert

Deine Aktion

15. April 2026 (vorbei)

Script Editor nur noch lesbar. Keine neuen Scripts. Keine Änderungen an bestehenden Scripts.

Bestehende Scripts werden weiterhin ausgeführt. Jetzt migrieren oder deine Logik einfrieren.

30. Juni 2026

Alle Shopify Scripts hören auf zu laufen. Punkt.

Dein Ersatz durch eine Function muss vor diesem Datum live sein.

Die Migration ist binär. Entweder ist deine Function bis zum 30. Juni bereitgestellt und dein Checkout funktioniert weiter, oder sie ist es nicht — und jeder betroffene Warenkorb fällt stillschweigend auf Standardpreise, Standard-Versandtarife und alle aktivierten Zahlungsmethoden zurück. Es gibt keine Teilpunkte. Das Script läuft entweder oder eben nicht, und nach dem 30. Juni läuft es nicht mehr.

Tipp: Öffne Settings → Checkout → Customizations Report in deinem Shopify-Admin. Dort sind alle aktiven Scripts in deinem Store aufgeführt, was sie tun und welcher Function-Typ als Ersatz empfohlen wird. Fang dort an.

Functions vs. Scripts: Was sich tatsächlich geändert hat

Dimension

Shopify Scripts (veraltet)

Shopify Functions (Ersatz)

Sprache

Ruby DSL (Shopify-spezifisch)

Rust, JavaScript, TypeScript

Runtime

Sandboxed Ruby auf Shopify-Infrastruktur

WebAssembly (WASM) — Ausführung unter 5 ms

Plan-Verfügbarkeit

Nur Plus

Alle Pläne (benutzerdefinierte Apps erfordern Plus; öffentliche Apps sind offen)

Editor

Script Editor im Admin

Lokale IDE + Shopify CLI

Versionierung

Keine — Live-Änderungen

Git-freundlich — vollständige Versionskontrolle

Testen

Manuell im Checkout

Lokale Entwicklung mit shopify app dev, Preview-Links

Bereitstellung

Im Admin auf „Speichern“ klicken

shopify app deploy im Terminal

Ziele

Line Items, Versand, Zahlungen

Rabatte, Cart Transform, Validation, Delivery Customization, Payment Customization, Order Routing, Fulfillment Constraints, mehr

Der architektonische Wandel ist wichtig. Scripts waren „Ruby in einem Textfeld anpassen“. Functions sind „eine echte App schreiben, per Versionskontrolle verwalten, lokal testen und über eine echte CI-Pipeline bereitstellen“. Das ist ein steilerer Einstieg. Es ist auch die letzte Migration, die du in absehbarer Zeit für Checkout-Logik machst — Functions sind Shopifys langfristiges Bekenntnis und nicht nur ein Provisorium wie es Scripts letztlich waren.

Deine Scripts dem richtigen Function-Typ zuordnen

Jedes Script, das du heute hast, lässt sich genau einer Function-API zuordnen. Hier ist die Lookup-Tabelle, die du dir an den Monitor heften solltest.

Alter Script-Typ

Was es tat

Neue Function-API

Function-Ziel

Line Item Script

Rabatte auf bestimmte Produkte / Kunden / Warenkorb-Bedingungen anwenden

Cart & Checkout Discounts API

cart.lines.discounts.generate.run

Shipping Script (Rabatt)

Kostenloser / vergünstigter Versand basierend auf Warenkorbregeln

Cart & Checkout Discounts API

cart.delivery-options.discounts.generate.run

Shipping Script (ausblenden / umbenennen / umsortieren)

Einen Versandtarif über $X ausblenden, „Standard“ in „Kostenlos ab $50“ umbenennen

Delivery Customization API

cart.delivery-options.transform.run

Payment Script

PayPal für B2B ausblenden, Nachnahme über $500 ausblenden, Zahlungsmethoden umsortieren

Payment Customization API

cart.payment-methods.transform.run

Cart-modifying Script (selten)

Produkte bündeln, Line Items austauschen

Cart Transform API

cart.transform.run

Checkout blockierendes Script

Warenkorb ablehnen, wenn die SKU-Mischung ungültig ist

Cart & Checkout Validation API

cart.validations.generate.run

Wenn du zehn Scripts hast, wirst du wahrscheinlich drei bis fünf Functions bauen — mehrere Scripts lassen sich oft in einer Function mit saubererer Verzweigungslogik zusammenführen.


Shopify Functions unifying discounts, delivery, and payment customizations

Voraussetzung: Lokale Entwicklungsumgebung einrichten

Bevor du irgendeine Function scaffoldest, brauchst du drei Dinge lokal installiert. Führe diese Prüfungen in deinem Terminal aus.

1. Node.js 18+

node --version
# Must be >= 18.0.0
node --version
# Must be >= 18.0.0

Wenn älter, installiere es über nvm oder lade es von nodejs.org herunter.

2. Shopify CLI 3+

npm install -g @shopify/cli@latest
shopify version
# Should output 3.x or higher
npm install -g @shopify/cli@latest
shopify version
# Should output 3.x or higher

3. Rust-Toolchain (nur wenn du Functions in Rust schreiben willst)

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add wasm32-wasip1
cargo --version
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add wasm32-wasip1
cargo --version

JavaScript-Functions brauchen kein Rust. Wähle für dein Team eine Sprache und bleib dabei — beide zu mischen erhöht den Wartungsaufwand.

4. Einen Development Store

Melde dich entweder im Partner-Dashboard an und erstelle einen neuen Development Store oder verwende einen vorhandenen. Du wirst Functions zunächst in diesen Store deployen, bevor du sie in die Produktion überführst.

Deine erste Function scaffolden

Die CLI erledigt den Großteil des Boilerplates. In jedem Verzeichnis:

# Create a new Shopify app (skip if you already have one)
shopify app init my-checkout-functions
cd my-checkout-functions

# Generate a Function extension
shopify app generate extension
# Create a new Shopify app (skip if you already have one)
shopify app init my-checkout-functions
cd my-checkout-functions

# Generate a Function extension
shopify app generate extension

Die CLI führt dich durch die Abfragen. Für eine Discount-Function würdest du wählen:

  • Typ: Function

  • Template: discount (oder cart_checkout_validation, delivery_customization, payment_customization usw.)

  • Sprache: Rust oder JavaScript

  • Name: etwas wie volume-discount-fn

Dadurch wird extensions/volume-discount-fn/ mit Folgendem erstellt:

extensions/volume-discount-fn/
├── shopify.extension.toml      # Function config targets, build, version
├── src/
├── cart_lines_discounts_generate_run.graphql   # Input query
└── cart_lines_discounts_generate_run.rs        # Function logic
├── Cargo.toml                  # Rust dependencies (Rust only)
└── README.md
extensions/volume-discount-fn/
├── shopify.extension.toml      # Function config targets, build, version
├── src/
├── cart_lines_discounts_generate_run.graphql   # Input query
└── cart_lines_discounts_generate_run.rs        # Function logic
├── Cargo.toml                  # Rust dependencies (Rust only)
└── README.md

Die drei Dateien, die du ständig bearbeiten wirst, sind die .toml (Konfiguration), die .graphql (Eingabe) und die .rs / .js (Logik). Das ist alles.

Tutorial 1: Ersetzen eines Line Item Scripts (Volumenrabatt)

Angenommen, dein altes Script gab 10 % Rabatt auf den Warenkorbzwischensumme, sobald der Warenkorb 5+ Einheiten aus einer bestimmten Kollektion enthielt. Hier ist das entsprechende Function-Gegenstück.

Schritt 1.1: die Konfiguration (shopify.extension.toml)

api_version = "2026-01"

[[extensions]]
name = "volume-discount-fn"
handle = "volume-discount-fn"
type = "function"

[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/cart_lines_discounts_generate_run.graphql"
export = "cart_lines_discounts_generate_run"

[extensions.build]
command = "cargo build --target=wasm32-wasip1 --release"
path = "target/wasm32-wasip1/release/volume-discount-fn.wasm"
watch = ["src/**/*.rs"]
api_version = "2026-01"

[[extensions]]
name = "volume-discount-fn"
handle = "volume-discount-fn"
type = "function"

[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/cart_lines_discounts_generate_run.graphql"
export = "cart_lines_discounts_generate_run"

[extensions.build]
command = "cargo build --target=wasm32-wasip1 --release"
path = "target/wasm32-wasip1/release/volume-discount-fn.wasm"
watch = ["src/**/*.rs"]

Schritt 1.2: die Eingabeabfrage (src/cart_lines_discounts_generate_run.graphql)

query Input {
  cart {
    lines {
      id
      quantity
      cost {
        subtotalAmount {
          amount
        }
      }
      merchandise {
        ... on ProductVariant {
          product {
            inAnyCollection(ids: ["gid://shopify/Collection/123456789"])
          }
        }
      }
    }
  }
  discount {
    discountClasses
  }
}
query Input {
  cart {
    lines {
      id
      quantity
      cost {
        subtotalAmount {
          amount
        }
      }
      merchandise {
        ... on ProductVariant {
          product {
            inAnyCollection(ids: ["gid://shopify/Collection/123456789"])
          }
        }
      }
    }
  }
  discount {
    discountClasses
  }
}

Tipp: Functions sehen nur die Daten, die du abfragst. Halte GraphQL minimal — jedes Feld, das du weglässt, bedeutet eine schnellere und günstigere Ausführung.

Schritt 1.3: die Logik (src/cart_lines_discounts_generate_run.rs)

use super::schema;
use shopify_function::prelude::*;
use shopify_function::Result;

#[shopify_function]
fn cart_lines_discounts_generate_run(
    input: schema::cart_lines_discounts_generate_run::Input,
) -> Result<schema::CartLinesDiscountsGenerateRunResult> {
    // Bail if discount class doesn't match
    let has_order_discount = input
        .discount()
        .discount_classes()
        .contains(&schema::DiscountClass::Order);

    if !has_order_discount {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Sum quantities of items in the target collection
    let qualifying_qty: i64 = input
        .cart()
        .lines()
        .iter()
        .filter(|line| {
            if let schema::Merchandise::ProductVariant(v) = line.merchandise() {
                *v.product().in_any_collection()
            } else {
                false
            }
        })
        .map(|line| *line.quantity())
        .sum();

    if qualifying_qty < 5 {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Apply 10% off the order subtotal
    Ok(schema::CartLinesDiscountsGenerateRunResult {
        operations: vec![schema::CartOperation::OrderDiscountsAdd(
            schema::OrderDiscountsAddOperation {
                selection_strategy: schema::OrderDiscountSelectionStrategy::First,
                candidates: vec![schema::OrderDiscountCandidate {
                    targets: vec![schema::OrderDiscountCandidateTarget::OrderSubtotal(
                        schema::OrderSubtotalTarget {
                            excluded_cart_line_ids: vec![],
                        },
                    )],
                    message: Some("Volume discount: 10% off".to_string()),
                    value: schema::OrderDiscountCandidateValue::Percentage(
                        schema::Percentage { value: Decimal(10.0) }
                    ),
                    conditions: None,
                    associated_discount_code: None,
                }],
            },
        )],
    })
}
use super::schema;
use shopify_function::prelude::*;
use shopify_function::Result;

#[shopify_function]
fn cart_lines_discounts_generate_run(
    input: schema::cart_lines_discounts_generate_run::Input,
) -> Result<schema::CartLinesDiscountsGenerateRunResult> {
    // Bail if discount class doesn't match
    let has_order_discount = input
        .discount()
        .discount_classes()
        .contains(&schema::DiscountClass::Order);

    if !has_order_discount {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Sum quantities of items in the target collection
    let qualifying_qty: i64 = input
        .cart()
        .lines()
        .iter()
        .filter(|line| {
            if let schema::Merchandise::ProductVariant(v) = line.merchandise() {
                *v.product().in_any_collection()
            } else {
                false
            }
        })
        .map(|line| *line.quantity())
        .sum();

    if qualifying_qty < 5 {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Apply 10% off the order subtotal
    Ok(schema::CartLinesDiscountsGenerateRunResult {
        operations: vec![schema::CartOperation::OrderDiscountsAdd(
            schema::OrderDiscountsAddOperation {
                selection_strategy: schema::OrderDiscountSelectionStrategy::First,
                candidates: vec![schema::OrderDiscountCandidate {
                    targets: vec![schema::OrderDiscountCandidateTarget::OrderSubtotal(
                        schema::OrderSubtotalTarget {
                            excluded_cart_line_ids: vec![],
                        },
                    )],
                    message: Some("Volume discount: 10% off".to_string()),
                    value: schema::OrderDiscountCandidateValue::Percentage(
                        schema::Percentage { value: Decimal(10.0) }
                    ),
                    conditions: None,
                    associated_discount_code: None,
                }],
            },
        )],
    })
}

Schritt 1.4: Testen, deployen, aktivieren

# Local development with hot reload
shopify app dev

# When ready, deploy
shopify app deploy

# In the GraphiQL panel that opens (press `g` in the dev terminal),
# create the automatic discount that uses your Function:
# Local development with hot reload
shopify app dev

# When ready, deploy
shopify app deploy

# In the GraphiQL panel that opens (press `g` in the dev terminal),
# create the automatic discount that uses your Function:
mutation {
  discountAutomaticAppCreate(
    automaticAppDiscount: {
      title: "Volume Discount (5+ collection items)"
      functionHandle: "volume-discount-fn"
      discountClasses: [ORDER]
      startsAt: "2026-04-16T00:00:00Z"
    }
  ) {
    automaticAppDiscount { discountId }
    userErrors { field message }
  }
}
mutation {
  discountAutomaticAppCreate(
    automaticAppDiscount: {
      title: "Volume Discount (5+ collection items)"
      functionHandle: "volume-discount-fn"
      discountClasses: [ORDER]
      startsAt: "2026-04-16T00:00:00Z"
    }
  ) {
    automaticAppDiscount { discountId }
    userErrors { field message }
  }
}

Das war's. Die Function ist live, versionskontrolliert und ersetzt das alte Script vollständig.

Tutorial 2: Ersetzen eines Shipping Scripts (Methode oberhalb eines Warenkorb-Schwellenwerts ausblenden)

Ein häufiges Script: „Expressversand ausblenden, wenn die Warenkorb-Zwischensumme über $500 liegt, um teuren Overnight-Versand bei großen Bestellungen zu vermeiden.“ Hier ist die Version als Delivery Customization Function.

Schritt 2.1: Scaffolden

shopify app generate extension --template delivery_customization --name hide-express-fn
shopify app generate extension --template delivery_customization --name hide-express-fn

Schritt 2.2: Eingabeabfrage (src/run.graphql)

query Input {
  cart {
    cost {
      subtotalAmount {
        amount
      }
    }
    deliveryGroups {
      deliveryOptions {
        handle
        title
      }
    }
  }
}
query Input {
  cart {
    cost {
      subtotalAmount {
        amount
      }
    }
    deliveryGroups {
      deliveryOptions {
        handle
        title
      }
    }
  }
}

Schritt 2.3: Logik (src/run.js — JavaScript-Variante)

// @ts-check
/**
 * @typedef {import("../generated/api").RunInput} RunInput
 * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult
 */

const NO_CHANGES = { operations: [] };
const THRESHOLD = 500.0;
const HIDE_TITLES = ["Express", "Overnight"];

/**
 * @param {RunInput} input
 * @returns {FunctionRunResult}
 */
export function run(input) {
  const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount);
  if (subtotal < THRESHOLD) return NO_CHANGES;

  const operations = input.cart.deliveryGroups.flatMap((group) =>
    group.deliveryOptions
      .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t)))
      .map((opt) => ({
        hide: { deliveryOptionHandle: opt.handle },
      }))
  );

  return { operations };
}
// @ts-check
/**
 * @typedef {import("../generated/api").RunInput} RunInput
 * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult
 */

const NO_CHANGES = { operations: [] };
const THRESHOLD = 500.0;
const HIDE_TITLES = ["Express", "Overnight"];

/**
 * @param {RunInput} input
 * @returns {FunctionRunResult}
 */
export function run(input) {
  const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount);
  if (subtotal < THRESHOLD) return NO_CHANGES;

  const operations = input.cart.deliveryGroups.flatMap((group) =>
    group.deliveryOptions
      .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t)))
      .map((opt) => ({
        hide: { deliveryOptionHandle: opt.handle },
      }))
  );

  return { operations };
}

Schritt 2.4: Über den Admin aktivieren (kein GraphQL nötig)

Delivery Customizations haben eine integrierte Admin-Oberfläche. Nach shopify app deploy:

  1. Gehe zu Settings → Shipping and delivery

  2. Scrolle zum Abschnitt Customizations unten auf der Seite

  3. Klicke auf Add customization → wähle deine Function aus

  4. Speichern

Die Ausblendungsregel ist in der Produktion live. Keine Mutation erforderlich.


Shopify delivery customization Function hiding shipping option at checkout

Tutorial 3: Ersetzen eines Payment Scripts (Nachnahme für B2B ausblenden)

Altes Script: „Nachnahme für jeden Kunden mit dem Tag 'B2B' ausblenden.“ Hier ist die Version für Payment Customization.

Schritt 3.1: Scaffolden

shopify app generate extension --template payment_customization --name hide-cod-b2b-fn
shopify app generate extension --template payment_customization --name hide-cod-b2b-fn

Schritt 3.2: Eingabeabfrage

query Input {
  cart {
    buyerIdentity {
      customer {
        hasTags(tags: [{ tag: "B2B" }]) {
          tag
          hasTag
        }
      }
    }
  }
  paymentMethods {
    id
    name
  }
}
query Input {
  cart {
    buyerIdentity {
      customer {
        hasTags(tags: [{ tag: "B2B" }]) {
          tag
          hasTag
        }
      }
    }
  }
  paymentMethods {
    id
    name
  }
}

Schritt 3.3: Logik (src/run.js)

const NO_CHANGES = { operations: [] };

export function run(input) {
  const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0];
  const isB2B = tagCheck?.hasTag === true;
  if (!isB2B) return NO_CHANGES;

  const codMethod = input.paymentMethods.find((pm) =>
    pm.name.toLowerCase().includes("cash on delivery")
  );
  if (!codMethod) return NO_CHANGES;

  return {
    operations: [{ hide: { paymentMethodId: codMethod.id } }],
  };
}
const NO_CHANGES = { operations: [] };

export function run(input) {
  const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0];
  const isB2B = tagCheck?.hasTag === true;
  if (!isB2B) return NO_CHANGES;

  const codMethod = input.paymentMethods.find((pm) =>
    pm.name.toLowerCase().includes("cash on delivery")
  );
  if (!codMethod) return NO_CHANGES;

  return {
    operations: [{ hide: { paymentMethodId: codMethod.id } }],
  };
}

Schritt 3.4: Aktivieren

Payment Customizations haben ebenfalls eine Admin-Oberfläche unter Settings → Payments → Customizations. Derselbe Ablauf wie beim Versand — Function auswählen, speichern, fertig.

Weil du das hier liest — ein Wort zu Post-Purchase

Eine kurze Offenlegung, da dies der Revize-Blog ist. Revize kümmert sich um die Dinge, die Functions nicht anfassen können — sobald eine Bestellung aufgegeben wurde, wollen Kunden einen Artikel hinzufügen, eine Größe tauschen, die Lieferadresse korrigieren oder einen vergessenen Rabatt anwenden. Functions sitzen im Checkout. Revize sitzt danach. Functions entscheiden, was im Warenkorb erlaubt ist; Revize gibt deinen Kunden und deinem Support-Team die Möglichkeit, die Bestellung danach zu bearbeiten, ohne einen Refund-und-Neuaufbau-Zyklus. Das ist für zwei Arten von Stores wichtig: für jene mit so viel Bestellvolumen, dass manuelle Bearbeitung zusammenbricht (Plus-Betreiber natürlich, aber auch hochfrequentierte Advanced-Stores), und für jene, deren gesamte Marke auf Kundenerlebnis basiert — wo eine „Entschuldigung, das können wir nicht ändern“-E-Mail Wiederkäufe killt.

Wenn dein Migrationsplan Scripts → Functions abdeckt, du aber Post-Purchase-Bestelländerungen noch nie sauber sortiert hast, stößt du in etwa drei Wochen an die nächste „Warum ist das so schwer?“-Wand. Der Bestellverwaltungs-Leitfaden, den wir gerade veröffentlicht haben zeigt den vollständigen Post-Checkout-Plan.

Zurück zur Migration.

Teststrategie: Das Muster mit markierten Kunden

Functions haben keinen „Entwurfsmodus“, den du im Admin umschalten kannst. Das professionelle Muster ist, die neue Function an einem Kunden-Tag zu koppeln, das alte Script und die neue Function parallel laufen zu lassen, zu prüfen, ob sie für markierte Nutzer identische Ergebnisse liefern, und dann den Schalter umzulegen.

Schritt 1: Testnutzer taggen

Füge unter Kunden zwei oder drei internen Konten den Tag FN-TESTER hinzu.

Schritt 2: Die Function an das Vorhandensein des Tags verzweigen

// At the top of your run function
let is_tester = input
    .cart()
    .buyer_identity()
    .and_then(|bi| bi.customer())
    .map(|c| c.has_any_tag())
    .unwrap_or(&false);

if !*is_tester {
    return Ok(default_result);  // Fall through to existing Script
}

// New Function logic only runs for tagged users
// At the top of your run function
let is_tester = input
    .cart()
    .buyer_identity()
    .and_then(|bi| bi.customer())
    .map(|c| c.has_any_tag())
    .unwrap_or(&false);

if !*is_tester {
    return Ok(default_result);  // Fall through to existing Script
}

// New Function logic only runs for tagged users

Schritt 3: hasAnyTag zu deiner Eingabeabfrage hinzufügen

cart {
  buyerIdentity {
    customer {
      hasAnyTag(tags: ["FN-TESTER"])
    }
  }
}
cart {
  buyerIdentity {
    customer {
      hasAnyTag(tags: ["FN-TESTER"])
    }
  }
}

Schritt 4: Im Checkout verifizieren

Melde dich als markierter Nutzer an, gehe durch den Checkout und bestätige, dass die Function ausgelöst wird. Melde dich als unmarkierter Nutzer an und bestätige, dass das alte Script weiterhin läuft. Wenn die Parität einige Tage lang hält, entferne die Tag-Prüfung und lass die Function für alle laufen.

Schritt 5: Das alte Script unveröffentlichen

Gehe zu Apps → Script Editor → [Dein Script] → Unpublish. Sobald es unveröffentlicht ist, ist die Function die einzige Quelle der Wahrheit.

Ein Bereitstellungs-Workflow, der wirklich skaliert

Deploye nicht für immer vom Laptop eines Entwicklers aus. Sobald du ein oder zwei Scripts migriert hast, richte eine echte CI-Pipeline ein.

Der minimal brauchbare Workflow

# .github/workflows/deploy-functions.yml
name: Deploy Shopify Functions
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - uses: dtolnay/rust-toolchain@stable
        with: { targets: wasm32-wasip1 }
      - run: npm install -g @shopify/cli@latest
      - run: shopify app deploy --force
        env:
          SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
# .github/workflows/deploy-functions.yml
name: Deploy Shopify Functions
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - uses: dtolnay/rust-toolchain@stable
        with: { targets: wasm32-wasip1 }
      - run: npm install -g @shopify/cli@latest
      - run: shopify app deploy --force
        env:
          SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}

Generiere das Partner-Token in deinem Partner-Dashboard unter Settings → Tokens. Ab jetzt liefert jeder Merge nach main deine Functions aus. Keine Slack-Threads mehr à la „Hat Mike das deployed?“

Versionierung und Rollback

shopify app deploy erstellt einen versionierten Snapshot. Für ein Rollback:

shopify app versions list
shopify app release --version <previous-version-id

shopify app versions list
shopify app release --version <previous-version-id

Im Vergleich zu Scripts — wo Rollback bedeutete: „Erinnere dich an den alten Code und füge ihn wieder ein“ — ist das ein Unterschied wie Tag und Nacht.


Shopify Functions deployment pipeline across local staging and production environments

Was die meisten Teams falsch machen

Nachdem wir Plus-Händler im letzten Jahr durch diese Migration begleitet haben, tauchen immer wieder dieselben fünf Fehler auf.

1. Functions als 1:1-Port eines Scripts zu behandeln. Das sind sie nicht. Eine einzige Function kann drei Scripts mit saubererer Verzweigungslogik ersetzen. Prüfe deine Scripts als System, bevor du sie neu schreibst.

2. Die Leseberechtigungen zu vergessen. Viele Functions benötigen read_customers, read_orders oder write_discounts. Füge sie in shopify.app.toml unter scopes hinzu und autorisiere die App neu, sonst liefert deine Eingabeabfrage null zurück.

3. Functions mit nicht getaggten Kunden ohne Paritätstest laufen zu lassen. Selbst wenn dein Code richtig aussieht, werden Randfälle (leerer Warenkorb, Geschenkkarten, Store Credit, B2B-Entwürfe) Probleme aufdecken. Eine tag-gesteuerte Ausrollung kostet dich zwei Tage und erspart dir einen P1-Ausfall.

4. Den Customizations Report zu überspringen. Er ist das beste Inventar dessen, was tatsächlich läuft. Migriere nicht aus dem Gedächtnis — migriere aus dem Report.

5. Kollektion-IDs und Kundentags hart zu verdrahten. Verwende Function-Konfiguration über Metafelder, wenn du vom Händler anpassbare Werte brauchst. Die CLI kann Metafeld-gestützte Konfiguration scaffolden — siehe Shopifys Doku zur Function-Konfiguration.

Migrations-Checkliste für die nächsten 75 Tage

Ein realistischer Wochen-für-Wochen-Plan, um bis zum 30. Juni ruhig ans Ziel zu kommen.

Woche

Aktion

Woche 1 (diese Woche)

Ziehe den Customizations Report. Erfasse jedes Script. Entscheide: Function vs. öffentliche App vs. löschen.

Wochen 2–3

Lokale Entwicklungsumgebung einrichten. Die erste Function scaffolden. Das einfachste Script migrieren (meist eine Regel zum Ausblenden von Zahlungen).

Wochen 4–6

Discount-Scripts migrieren. Diese dauern am längsten, weil die Discounts API am umfangreichsten ist. Gründlich per Tag testen.

Wochen 7–8

Shipping-/Delivery-Scripts migrieren. Delivery Customizations über den Admin aktivieren.

Wochen 9–10

CI-Pipeline einrichten. Alle Bereitstellungen von Entwickler-Laptops wegziehen.

Woche 11 (Mitte Juni)

Abschließende Paritätsprüfung. Alle Scripts unveröffentlichen. Den Store zwei Wochen lang nur auf Functions laufen lassen.

30. Juni

Der Stichtag ist da. Nichts bricht, weil du früh fertig geworden bist.

Wenn du diese Woche startest, hast du Puffer. Wenn du im Juni startest, hast du keinen.


Week-by-week migration roadmap from Shopify Scripts to Functions

Häufig gestellte Fragen

Brauche ich Shopify Plus, um Functions zu nutzen?

Benutzerdefinierte Functions erfordern Shopify Plus, aber Functions aus öffentlichen Apps funktionieren in jedem Plan. Wenn du nicht auf Plus bist, hast du zwei Wege: Installiere eine öffentliche App aus dem Shopify App Store, die die Function für dich liefert, oder upgrade auf Plus, um deine eigenen benutzerdefinierten Functions zu schreiben. Die meisten großen Händler, die Scripts hatten, hatten ohnehin bereits Plus, also ändert sich praktisch selten etwas.

Kann ich Functions in TypeScript schreiben?

Ja — TypeScript wird vollständig unterstützt und die CLI scaffoldet es für dich. Wenn du shopify app generate extension ausführst und „JavaScript“ auswählst, enthält das generierte Projekt Typdeklarationen aus import("../generated/api"). Du kannst Dateien in .ts umwandeln und eine tsconfig.json hinzufügen, wenn du möchtest. Die kompilierte Ausgabe (WASM) ist unabhängig von der Quellsprache identisch.

Wie schnell sind Functions im Vergleich zu Scripts?

Functions werden typischerweise in unter 5 ms ausgeführt — deutlich schneller als Ruby-Scripts. Da sie zu WebAssembly kompiliert und in einer schlanken Runtime ausgeführt werden, setzt Shopify ein Ausführungsbudget von 5 ms durch. Wenn deine Function es überschreitet, wird die Operation verworfen und deine Function gibt keine Operationen zurück. In der Praxis benötigt eine gut geschriebene Function 1–2 ms. Die Performance-Obergrenze ist deutlich höher als bei Scripts.

Kann eine Function eine externe API aufrufen?

Nein — Functions können keine Netzwerkrequests ausführen. Sie sind reine Berechnung: Eingabedaten aus dem Warenkorb → Ausgabe von Operationen. Wenn du externe Daten brauchst (CRM-Lookup, Echtzeit-Bestandsprüfung), musst du die Daten entweder im Voraus in Metafeldern speichern oder eine andere Oberfläche verwenden (App Proxy, Webhooks, Cart Transform mit Backend-Lookup). Das ist der häufigste Grund, warum Teams neu entwerfen statt nur portieren müssen.

Was ist der Unterschied zwischen Cart Transform und Discounts?

Discounts ändern Preise; Cart Transform ändert den Inhalt des Warenkorbs. Verwende die Discounts API für 10 % Rabatt, kostenlosen Versand oder BOGO. Verwende Cart Transform, um zwei Produkte zu einem Line Item zu bündeln oder eine Variante in mehrere aufzusplitten. Viele alte Scripts vermischten beides — trenne es bei der Migration in zwei Functions.

Wie teste ich eine Function lokal ohne Development Store?

Du kannst Unit-Tests mit cargo test (Rust) oder npm test (JS) ausführen, aber vollständige Integrationstests erfordern einen Development Store. Die CLI bietet shopify app function run, womit du deine Function gegen eine Beispiel-Eingabedatei ausführst — nützlich für schnelles Iterieren. Aber um das Checkout-Verhalten end-to-end zu bestätigen, brauchst du einen echten Store mit einem echten Warenkorb.

Kann ich mehrere Functions desselben Typs haben?

Ja — Shopify unterstützt mehrere Functions pro Ziel, und sie werden in deterministischer Reihenfolge ausgeführt. Bei Rabatten wird die Reihenfolge durch Shopifys Regeln zum Stacking von Rabatten bestimmt. Bei Delivery- und Payment-Customizations kannst du Functions aneinanderreihen, aber jede Ausgabe speist die nächste. Die meisten Teams verwenden aus Einfachheitsgründen eine Function pro Typ.

Was passiert mit meinem Script, nachdem ich die Function deployed habe?

Beide laufen parallel, bis du das Script in Apps → Script Editor unveröffentlichst. Das ist beabsichtigt — so erhältst du das Testfenster für den Parallelbetrieb. Nachdem du bestätigt hast, dass die Function funktioniert, veröffentliche das Script manuell nicht mehr. Nach dem 30. Juni 2026 stoppen alle Scripts die Ausführung, unabhängig davon, ob du sie unveröffentlicht hast oder nicht.

Wird die Migration mein SEO oder mein Theme beeinflussen?

Nein — Functions laufen serverseitig im Checkout und berühren weder dein Theme noch deine Produktseiten. Sie ändern nur Rabatte, Versandoptionen und Zahlungsmethoden im Checkout. Dein Storefront, deine Produktvorlagen und dein SEO bleiben völlig unberührt.

Wie migriere ich ein Script, das Input.line_items mit benutzerdefinierten Properties verwendet?

Benutzerdefinierte Properties sind über das attribute-Feld auf den Cart-Lines in der GraphQL-Eingabe zugänglich. Füge attribute(key: "your-key") { value } innerhalb der lines-Auswahl hinzu. Die Function liest es genauso, wie Scripts Line-Item-Properties lesen — nur über GraphQL statt über Ruby-Methodenaufrufe.

Was ist mit Analytics und Order-Tags? Können Functions Daten schreiben?

Functions können keine Order-Tags schreiben oder Webhooks selbst auslösen — sie geben nur Operationen für den aktuellen Warenkorb zurück. Für Tagging oder nachgelagerte Workflows verwende Shopify Flow, ausgelöst durch das Ereignis der Auftragserstellung. Viele Händler kombinieren eine Function (für den Rabatt) mit einem Flow (um die Bestellung mit „VOLUME-DISCOUNT-APPLIED“ zu taggen).

Gibt es eine öffentliche App, die ich installieren kann, statt eine benutzerdefinierte Function zu bauen?

Ja — im Shopify App Store gibt es Dutzende Apps, die Functions für gängige Anwendungsfälle verpacken. Suche nach „discount function“, „delivery customization“ oder „payment customization“. Für einfache Anwendungsfälle (Volumenrabatte, Zahlungsmethoden nach Tag ausblenden, kostenloser Versand über X) kann eine vorhandene App dir Tage an Entwicklungsarbeit sparen. Reserviere benutzerdefinierte Functions für Logik, die wirklich einzigartig für dein Geschäft ist.

Was passiert, wenn ich die Frist am 30. Juni verpasse?

Das Script stoppt die Ausführung — es gibt keinen Fallback, keine Schonfrist und keine Verlängerung. Was auch immer das Script getan hat (der Rabatt, der ausgeblendete Versandtarif, die blockierte Zahlungsmethode), fällt um Mitternacht UTC am 1. Juli auf das Standardverhalten zurück. Wenn dein Geschäft von dieser Logik abhängt, plane, deutlich vor diesem Datum live zu sein. Die Migration dauert länger, als die meisten Teams schätzen, vor allem mit Paritätstests.

Kann ich die Script-Editor-App vollständig löschen?

Du kannst sie nach dem 30. Juni 2026 deinstallieren, aber Shopify wird sie wahrscheinlich automatisch entfernen. Sobald Scripts nicht mehr ausgeführt werden, erfüllt der Editor keinen Zweck mehr. Du kannst außerdem jetzt alle Scripts unveröffentlichen und die App sofort deinstallieren, wenn du die Migration abgeschlossen hast — deine Functions sind unabhängig.

Was du diese Woche tun solltest

Lies diesen Artikel nicht nur und schließe den Tab. Tue in den nächsten sieben Tagen diese vier Dinge.

1. Den Customizations Report ziehen. Gehe zu Settings → Checkout → Customizations Report. Exportiere ihn. Das ist dein Migrations-Backlog.

2. Deine Entwicklungsumgebung einrichten. Installiere Node 18+, Shopify CLI und Rust (falls relevant). Bestätige, dass shopify version funktioniert. Gesamtzeit: 30 Minuten.

3. Eine winzige Function scaffolden und in einen Development Store deployen. Wähle das einfachste Script, das du hast — meist eine Regel zum Ausblenden von Zahlungen. Migriere es end-to-end. Auch wenn es nie in Produktion geht, hast du damit den Toolchain-Stack validiert.

4. Kalenderzeit für die nächsten acht Wochen blocken. Migrationen passieren nicht zwischen zwei Sprints in Restmomenten. Blocke einen wiederkehrenden Slot — zum Beispiel jeden Dienstag- und Donnerstagnachmittag — und behandle ihn wie ein Release.

Aus den Teams, die wir migrieren gesehen haben, ist das Muster immer gleich: zwei Wochen Stillstand, drei Wochen eigentliche Arbeit, eine Woche Aufräumen. Das sind sechs Wochen. Du hast zehn. Den Puffer gibt es — verbrenne ihn in Code Review und QA, nicht im Aufschieben des Starts.

Und sobald deine Checkout-Logik sortiert ist, ist der nächste Punkt, den die meisten Teams angehen, Post-Purchase — Adressänderungen, Umtausch, Rabatt-Ergänzungen nachdem die Bestellung aufgegeben wurde. Wenn das auf deiner Roadmap steht (und das sollte es, egal ob du ein stark frequentierter Plus-Betreiber oder ein CX-orientierter Advanced-Store bist), Revize ist im Shopify App Store und arbeitet mit jeder Function zusammen, die du hier bauen wirst.

Ressourcen

Verwandte Artikel

Es ist der 16. April 2026. Gestern — der 15. April — hat Shopify den Script Editor endgültig gesperrt. Du kannst kein neues Script mehr erstellen oder veröffentlichen. Die Abschaltung der Ausführung erfolgt in 75 Tagen, am 30. Juni 2026.

Wenn du ein Shopify-Plus-Entwickler bist — oder die Agentur, die einen Plus-Store betreut — und diese Migration seit zwölf Monaten auf den „nächsten Sprint“ verschoben hast, hast du ein Problem. Kein „kann man später beheben“-Problem. Ein „dein Checkout bricht am 1. Juli um Mitternacht zusammen“-Problem. Die meisten Plus-Stores haben im Laufe der Jahre 5 bis 20 Scripts angesammelt, von denen jedes unauffällig eine Rabattregel, ein Ausblenden von Versandarten oder eine Zahlungssperre antreibt, an die sich niemand mehr erinnert.

Dieser Leitfaden ist das technische Migrationshandbuch, von dem wir uns im Januar gewünscht hätten, dass es existiert. Er deckt den eigentlichen Code ab — nicht nur die Strategie. Bis du fertig gelesen hast, weißt du, wie du mit der Shopify CLI eine Function scaffoldest, die Rust- oder JavaScript-Logik für Rabatte, Versandanpassungen und Zahlungsanpassungen schreibst, sie sicher gegen eine markierte Teilmenge deiner Kunden testest und sie produktiv ausrollst, ohne deinen bestehenden Checkout zu beschädigen.

Hol die Scripts aus deinem Store heraus und die Functions hinein.


Developer migrating Shopify Scripts to Shopify Functions modules

Kurzantwort: Scripts → Functions in 60 Sekunden

Die Migration in einem Absatz: Shopify Scripts (Ruby-Code im Script Editor, nur für Plus) werden durch Shopify Functions ersetzt (WebAssembly-Module, geschrieben in Rust oder JavaScript, für alle Pläne verfügbar). Du scaffoldest eine Function mit shopify app generate extension, schreibst eine run.graphql-Abfrage, die die benötigten Warenkorbdaten abruft, schreibst eine run.rs- oder run.js-Datei, die Operationen zurückgibt (Rabatte, ausgeblendete Versandarten usw.), deployest dann mit shopify app deploy und aktivierst sie über den Admin oder eine GraphQL-Mutation. Functions laufen als kompiliertes WASM mit unter 5 ms Latenz, funktionieren in jedem Plan und sind der einzige Anpassungsweg, den Shopify künftig unterstützt.

Was sich am 30. Juni tatsächlich ändert

Bevor wir irgendeinen Code anfassen, sollten wir die Daten richtig einordnen. Es gibt zwei davon, und beide sind wichtig.

Datum

Was passiert

Deine Aktion

15. April 2026 (vorbei)

Script Editor nur noch lesbar. Keine neuen Scripts. Keine Änderungen an bestehenden Scripts.

Bestehende Scripts werden weiterhin ausgeführt. Jetzt migrieren oder deine Logik einfrieren.

30. Juni 2026

Alle Shopify Scripts hören auf zu laufen. Punkt.

Dein Ersatz durch eine Function muss vor diesem Datum live sein.

Die Migration ist binär. Entweder ist deine Function bis zum 30. Juni bereitgestellt und dein Checkout funktioniert weiter, oder sie ist es nicht — und jeder betroffene Warenkorb fällt stillschweigend auf Standardpreise, Standard-Versandtarife und alle aktivierten Zahlungsmethoden zurück. Es gibt keine Teilpunkte. Das Script läuft entweder oder eben nicht, und nach dem 30. Juni läuft es nicht mehr.

Tipp: Öffne Settings → Checkout → Customizations Report in deinem Shopify-Admin. Dort sind alle aktiven Scripts in deinem Store aufgeführt, was sie tun und welcher Function-Typ als Ersatz empfohlen wird. Fang dort an.

Functions vs. Scripts: Was sich tatsächlich geändert hat

Dimension

Shopify Scripts (veraltet)

Shopify Functions (Ersatz)

Sprache

Ruby DSL (Shopify-spezifisch)

Rust, JavaScript, TypeScript

Runtime

Sandboxed Ruby auf Shopify-Infrastruktur

WebAssembly (WASM) — Ausführung unter 5 ms

Plan-Verfügbarkeit

Nur Plus

Alle Pläne (benutzerdefinierte Apps erfordern Plus; öffentliche Apps sind offen)

Editor

Script Editor im Admin

Lokale IDE + Shopify CLI

Versionierung

Keine — Live-Änderungen

Git-freundlich — vollständige Versionskontrolle

Testen

Manuell im Checkout

Lokale Entwicklung mit shopify app dev, Preview-Links

Bereitstellung

Im Admin auf „Speichern“ klicken

shopify app deploy im Terminal

Ziele

Line Items, Versand, Zahlungen

Rabatte, Cart Transform, Validation, Delivery Customization, Payment Customization, Order Routing, Fulfillment Constraints, mehr

Der architektonische Wandel ist wichtig. Scripts waren „Ruby in einem Textfeld anpassen“. Functions sind „eine echte App schreiben, per Versionskontrolle verwalten, lokal testen und über eine echte CI-Pipeline bereitstellen“. Das ist ein steilerer Einstieg. Es ist auch die letzte Migration, die du in absehbarer Zeit für Checkout-Logik machst — Functions sind Shopifys langfristiges Bekenntnis und nicht nur ein Provisorium wie es Scripts letztlich waren.

Deine Scripts dem richtigen Function-Typ zuordnen

Jedes Script, das du heute hast, lässt sich genau einer Function-API zuordnen. Hier ist die Lookup-Tabelle, die du dir an den Monitor heften solltest.

Alter Script-Typ

Was es tat

Neue Function-API

Function-Ziel

Line Item Script

Rabatte auf bestimmte Produkte / Kunden / Warenkorb-Bedingungen anwenden

Cart & Checkout Discounts API

cart.lines.discounts.generate.run

Shipping Script (Rabatt)

Kostenloser / vergünstigter Versand basierend auf Warenkorbregeln

Cart & Checkout Discounts API

cart.delivery-options.discounts.generate.run

Shipping Script (ausblenden / umbenennen / umsortieren)

Einen Versandtarif über $X ausblenden, „Standard“ in „Kostenlos ab $50“ umbenennen

Delivery Customization API

cart.delivery-options.transform.run

Payment Script

PayPal für B2B ausblenden, Nachnahme über $500 ausblenden, Zahlungsmethoden umsortieren

Payment Customization API

cart.payment-methods.transform.run

Cart-modifying Script (selten)

Produkte bündeln, Line Items austauschen

Cart Transform API

cart.transform.run

Checkout blockierendes Script

Warenkorb ablehnen, wenn die SKU-Mischung ungültig ist

Cart & Checkout Validation API

cart.validations.generate.run

Wenn du zehn Scripts hast, wirst du wahrscheinlich drei bis fünf Functions bauen — mehrere Scripts lassen sich oft in einer Function mit saubererer Verzweigungslogik zusammenführen.


Shopify Functions unifying discounts, delivery, and payment customizations

Voraussetzung: Lokale Entwicklungsumgebung einrichten

Bevor du irgendeine Function scaffoldest, brauchst du drei Dinge lokal installiert. Führe diese Prüfungen in deinem Terminal aus.

1. Node.js 18+

node --version
# Must be >= 18.0.0

Wenn älter, installiere es über nvm oder lade es von nodejs.org herunter.

2. Shopify CLI 3+

npm install -g @shopify/cli@latest
shopify version
# Should output 3.x or higher

3. Rust-Toolchain (nur wenn du Functions in Rust schreiben willst)

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add wasm32-wasip1
cargo --version

JavaScript-Functions brauchen kein Rust. Wähle für dein Team eine Sprache und bleib dabei — beide zu mischen erhöht den Wartungsaufwand.

4. Einen Development Store

Melde dich entweder im Partner-Dashboard an und erstelle einen neuen Development Store oder verwende einen vorhandenen. Du wirst Functions zunächst in diesen Store deployen, bevor du sie in die Produktion überführst.

Deine erste Function scaffolden

Die CLI erledigt den Großteil des Boilerplates. In jedem Verzeichnis:

# Create a new Shopify app (skip if you already have one)
shopify app init my-checkout-functions
cd my-checkout-functions

# Generate a Function extension
shopify app generate extension

Die CLI führt dich durch die Abfragen. Für eine Discount-Function würdest du wählen:

  • Typ: Function

  • Template: discount (oder cart_checkout_validation, delivery_customization, payment_customization usw.)

  • Sprache: Rust oder JavaScript

  • Name: etwas wie volume-discount-fn

Dadurch wird extensions/volume-discount-fn/ mit Folgendem erstellt:

extensions/volume-discount-fn/
├── shopify.extension.toml      # Function config targets, build, version
├── src/
├── cart_lines_discounts_generate_run.graphql   # Input query
└── cart_lines_discounts_generate_run.rs        # Function logic
├── Cargo.toml                  # Rust dependencies (Rust only)
└── README.md

Die drei Dateien, die du ständig bearbeiten wirst, sind die .toml (Konfiguration), die .graphql (Eingabe) und die .rs / .js (Logik). Das ist alles.

Tutorial 1: Ersetzen eines Line Item Scripts (Volumenrabatt)

Angenommen, dein altes Script gab 10 % Rabatt auf den Warenkorbzwischensumme, sobald der Warenkorb 5+ Einheiten aus einer bestimmten Kollektion enthielt. Hier ist das entsprechende Function-Gegenstück.

Schritt 1.1: die Konfiguration (shopify.extension.toml)

api_version = "2026-01"

[[extensions]]
name = "volume-discount-fn"
handle = "volume-discount-fn"
type = "function"

[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/cart_lines_discounts_generate_run.graphql"
export = "cart_lines_discounts_generate_run"

[extensions.build]
command = "cargo build --target=wasm32-wasip1 --release"
path = "target/wasm32-wasip1/release/volume-discount-fn.wasm"
watch = ["src/**/*.rs"]

Schritt 1.2: die Eingabeabfrage (src/cart_lines_discounts_generate_run.graphql)

query Input {
  cart {
    lines {
      id
      quantity
      cost {
        subtotalAmount {
          amount
        }
      }
      merchandise {
        ... on ProductVariant {
          product {
            inAnyCollection(ids: ["gid://shopify/Collection/123456789"])
          }
        }
      }
    }
  }
  discount {
    discountClasses
  }
}

Tipp: Functions sehen nur die Daten, die du abfragst. Halte GraphQL minimal — jedes Feld, das du weglässt, bedeutet eine schnellere und günstigere Ausführung.

Schritt 1.3: die Logik (src/cart_lines_discounts_generate_run.rs)

use super::schema;
use shopify_function::prelude::*;
use shopify_function::Result;

#[shopify_function]
fn cart_lines_discounts_generate_run(
    input: schema::cart_lines_discounts_generate_run::Input,
) -> Result<schema::CartLinesDiscountsGenerateRunResult> {
    // Bail if discount class doesn't match
    let has_order_discount = input
        .discount()
        .discount_classes()
        .contains(&schema::DiscountClass::Order);

    if !has_order_discount {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Sum quantities of items in the target collection
    let qualifying_qty: i64 = input
        .cart()
        .lines()
        .iter()
        .filter(|line| {
            if let schema::Merchandise::ProductVariant(v) = line.merchandise() {
                *v.product().in_any_collection()
            } else {
                false
            }
        })
        .map(|line| *line.quantity())
        .sum();

    if qualifying_qty < 5 {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Apply 10% off the order subtotal
    Ok(schema::CartLinesDiscountsGenerateRunResult {
        operations: vec![schema::CartOperation::OrderDiscountsAdd(
            schema::OrderDiscountsAddOperation {
                selection_strategy: schema::OrderDiscountSelectionStrategy::First,
                candidates: vec![schema::OrderDiscountCandidate {
                    targets: vec![schema::OrderDiscountCandidateTarget::OrderSubtotal(
                        schema::OrderSubtotalTarget {
                            excluded_cart_line_ids: vec![],
                        },
                    )],
                    message: Some("Volume discount: 10% off".to_string()),
                    value: schema::OrderDiscountCandidateValue::Percentage(
                        schema::Percentage { value: Decimal(10.0) }
                    ),
                    conditions: None,
                    associated_discount_code: None,
                }],
            },
        )],
    })
}

Schritt 1.4: Testen, deployen, aktivieren

# Local development with hot reload
shopify app dev

# When ready, deploy
shopify app deploy

# In the GraphiQL panel that opens (press `g` in the dev terminal),
# create the automatic discount that uses your Function:
mutation {
  discountAutomaticAppCreate(
    automaticAppDiscount: {
      title: "Volume Discount (5+ collection items)"
      functionHandle: "volume-discount-fn"
      discountClasses: [ORDER]
      startsAt: "2026-04-16T00:00:00Z"
    }
  ) {
    automaticAppDiscount { discountId }
    userErrors { field message }
  }
}

Das war's. Die Function ist live, versionskontrolliert und ersetzt das alte Script vollständig.

Tutorial 2: Ersetzen eines Shipping Scripts (Methode oberhalb eines Warenkorb-Schwellenwerts ausblenden)

Ein häufiges Script: „Expressversand ausblenden, wenn die Warenkorb-Zwischensumme über $500 liegt, um teuren Overnight-Versand bei großen Bestellungen zu vermeiden.“ Hier ist die Version als Delivery Customization Function.

Schritt 2.1: Scaffolden

shopify app generate extension --template delivery_customization --name hide-express-fn

Schritt 2.2: Eingabeabfrage (src/run.graphql)

query Input {
  cart {
    cost {
      subtotalAmount {
        amount
      }
    }
    deliveryGroups {
      deliveryOptions {
        handle
        title
      }
    }
  }
}

Schritt 2.3: Logik (src/run.js — JavaScript-Variante)

// @ts-check
/**
 * @typedef {import("../generated/api").RunInput} RunInput
 * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult
 */

const NO_CHANGES = { operations: [] };
const THRESHOLD = 500.0;
const HIDE_TITLES = ["Express", "Overnight"];

/**
 * @param {RunInput} input
 * @returns {FunctionRunResult}
 */
export function run(input) {
  const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount);
  if (subtotal < THRESHOLD) return NO_CHANGES;

  const operations = input.cart.deliveryGroups.flatMap((group) =>
    group.deliveryOptions
      .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t)))
      .map((opt) => ({
        hide: { deliveryOptionHandle: opt.handle },
      }))
  );

  return { operations };
}

Schritt 2.4: Über den Admin aktivieren (kein GraphQL nötig)

Delivery Customizations haben eine integrierte Admin-Oberfläche. Nach shopify app deploy:

  1. Gehe zu Settings → Shipping and delivery

  2. Scrolle zum Abschnitt Customizations unten auf der Seite

  3. Klicke auf Add customization → wähle deine Function aus

  4. Speichern

Die Ausblendungsregel ist in der Produktion live. Keine Mutation erforderlich.


Shopify delivery customization Function hiding shipping option at checkout

Tutorial 3: Ersetzen eines Payment Scripts (Nachnahme für B2B ausblenden)

Altes Script: „Nachnahme für jeden Kunden mit dem Tag 'B2B' ausblenden.“ Hier ist die Version für Payment Customization.

Schritt 3.1: Scaffolden

shopify app generate extension --template payment_customization --name hide-cod-b2b-fn

Schritt 3.2: Eingabeabfrage

query Input {
  cart {
    buyerIdentity {
      customer {
        hasTags(tags: [{ tag: "B2B" }]) {
          tag
          hasTag
        }
      }
    }
  }
  paymentMethods {
    id
    name
  }
}

Schritt 3.3: Logik (src/run.js)

const NO_CHANGES = { operations: [] };

export function run(input) {
  const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0];
  const isB2B = tagCheck?.hasTag === true;
  if (!isB2B) return NO_CHANGES;

  const codMethod = input.paymentMethods.find((pm) =>
    pm.name.toLowerCase().includes("cash on delivery")
  );
  if (!codMethod) return NO_CHANGES;

  return {
    operations: [{ hide: { paymentMethodId: codMethod.id } }],
  };
}

Schritt 3.4: Aktivieren

Payment Customizations haben ebenfalls eine Admin-Oberfläche unter Settings → Payments → Customizations. Derselbe Ablauf wie beim Versand — Function auswählen, speichern, fertig.

Weil du das hier liest — ein Wort zu Post-Purchase

Eine kurze Offenlegung, da dies der Revize-Blog ist. Revize kümmert sich um die Dinge, die Functions nicht anfassen können — sobald eine Bestellung aufgegeben wurde, wollen Kunden einen Artikel hinzufügen, eine Größe tauschen, die Lieferadresse korrigieren oder einen vergessenen Rabatt anwenden. Functions sitzen im Checkout. Revize sitzt danach. Functions entscheiden, was im Warenkorb erlaubt ist; Revize gibt deinen Kunden und deinem Support-Team die Möglichkeit, die Bestellung danach zu bearbeiten, ohne einen Refund-und-Neuaufbau-Zyklus. Das ist für zwei Arten von Stores wichtig: für jene mit so viel Bestellvolumen, dass manuelle Bearbeitung zusammenbricht (Plus-Betreiber natürlich, aber auch hochfrequentierte Advanced-Stores), und für jene, deren gesamte Marke auf Kundenerlebnis basiert — wo eine „Entschuldigung, das können wir nicht ändern“-E-Mail Wiederkäufe killt.

Wenn dein Migrationsplan Scripts → Functions abdeckt, du aber Post-Purchase-Bestelländerungen noch nie sauber sortiert hast, stößt du in etwa drei Wochen an die nächste „Warum ist das so schwer?“-Wand. Der Bestellverwaltungs-Leitfaden, den wir gerade veröffentlicht haben zeigt den vollständigen Post-Checkout-Plan.

Zurück zur Migration.

Teststrategie: Das Muster mit markierten Kunden

Functions haben keinen „Entwurfsmodus“, den du im Admin umschalten kannst. Das professionelle Muster ist, die neue Function an einem Kunden-Tag zu koppeln, das alte Script und die neue Function parallel laufen zu lassen, zu prüfen, ob sie für markierte Nutzer identische Ergebnisse liefern, und dann den Schalter umzulegen.

Schritt 1: Testnutzer taggen

Füge unter Kunden zwei oder drei internen Konten den Tag FN-TESTER hinzu.

Schritt 2: Die Function an das Vorhandensein des Tags verzweigen

// At the top of your run function
let is_tester = input
    .cart()
    .buyer_identity()
    .and_then(|bi| bi.customer())
    .map(|c| c.has_any_tag())
    .unwrap_or(&false);

if !*is_tester {
    return Ok(default_result);  // Fall through to existing Script
}

// New Function logic only runs for tagged users

Schritt 3: hasAnyTag zu deiner Eingabeabfrage hinzufügen

cart {
  buyerIdentity {
    customer {
      hasAnyTag(tags: ["FN-TESTER"])
    }
  }
}

Schritt 4: Im Checkout verifizieren

Melde dich als markierter Nutzer an, gehe durch den Checkout und bestätige, dass die Function ausgelöst wird. Melde dich als unmarkierter Nutzer an und bestätige, dass das alte Script weiterhin läuft. Wenn die Parität einige Tage lang hält, entferne die Tag-Prüfung und lass die Function für alle laufen.

Schritt 5: Das alte Script unveröffentlichen

Gehe zu Apps → Script Editor → [Dein Script] → Unpublish. Sobald es unveröffentlicht ist, ist die Function die einzige Quelle der Wahrheit.

Ein Bereitstellungs-Workflow, der wirklich skaliert

Deploye nicht für immer vom Laptop eines Entwicklers aus. Sobald du ein oder zwei Scripts migriert hast, richte eine echte CI-Pipeline ein.

Der minimal brauchbare Workflow

# .github/workflows/deploy-functions.yml
name: Deploy Shopify Functions
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - uses: dtolnay/rust-toolchain@stable
        with: { targets: wasm32-wasip1 }
      - run: npm install -g @shopify/cli@latest
      - run: shopify app deploy --force
        env:
          SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}

Generiere das Partner-Token in deinem Partner-Dashboard unter Settings → Tokens. Ab jetzt liefert jeder Merge nach main deine Functions aus. Keine Slack-Threads mehr à la „Hat Mike das deployed?“

Versionierung und Rollback

shopify app deploy erstellt einen versionierten Snapshot. Für ein Rollback:

shopify app versions list
shopify app release --version <previous-version-id

Im Vergleich zu Scripts — wo Rollback bedeutete: „Erinnere dich an den alten Code und füge ihn wieder ein“ — ist das ein Unterschied wie Tag und Nacht.


Shopify Functions deployment pipeline across local staging and production environments

Was die meisten Teams falsch machen

Nachdem wir Plus-Händler im letzten Jahr durch diese Migration begleitet haben, tauchen immer wieder dieselben fünf Fehler auf.

1. Functions als 1:1-Port eines Scripts zu behandeln. Das sind sie nicht. Eine einzige Function kann drei Scripts mit saubererer Verzweigungslogik ersetzen. Prüfe deine Scripts als System, bevor du sie neu schreibst.

2. Die Leseberechtigungen zu vergessen. Viele Functions benötigen read_customers, read_orders oder write_discounts. Füge sie in shopify.app.toml unter scopes hinzu und autorisiere die App neu, sonst liefert deine Eingabeabfrage null zurück.

3. Functions mit nicht getaggten Kunden ohne Paritätstest laufen zu lassen. Selbst wenn dein Code richtig aussieht, werden Randfälle (leerer Warenkorb, Geschenkkarten, Store Credit, B2B-Entwürfe) Probleme aufdecken. Eine tag-gesteuerte Ausrollung kostet dich zwei Tage und erspart dir einen P1-Ausfall.

4. Den Customizations Report zu überspringen. Er ist das beste Inventar dessen, was tatsächlich läuft. Migriere nicht aus dem Gedächtnis — migriere aus dem Report.

5. Kollektion-IDs und Kundentags hart zu verdrahten. Verwende Function-Konfiguration über Metafelder, wenn du vom Händler anpassbare Werte brauchst. Die CLI kann Metafeld-gestützte Konfiguration scaffolden — siehe Shopifys Doku zur Function-Konfiguration.

Migrations-Checkliste für die nächsten 75 Tage

Ein realistischer Wochen-für-Wochen-Plan, um bis zum 30. Juni ruhig ans Ziel zu kommen.

Woche

Aktion

Woche 1 (diese Woche)

Ziehe den Customizations Report. Erfasse jedes Script. Entscheide: Function vs. öffentliche App vs. löschen.

Wochen 2–3

Lokale Entwicklungsumgebung einrichten. Die erste Function scaffolden. Das einfachste Script migrieren (meist eine Regel zum Ausblenden von Zahlungen).

Wochen 4–6

Discount-Scripts migrieren. Diese dauern am längsten, weil die Discounts API am umfangreichsten ist. Gründlich per Tag testen.

Wochen 7–8

Shipping-/Delivery-Scripts migrieren. Delivery Customizations über den Admin aktivieren.

Wochen 9–10

CI-Pipeline einrichten. Alle Bereitstellungen von Entwickler-Laptops wegziehen.

Woche 11 (Mitte Juni)

Abschließende Paritätsprüfung. Alle Scripts unveröffentlichen. Den Store zwei Wochen lang nur auf Functions laufen lassen.

30. Juni

Der Stichtag ist da. Nichts bricht, weil du früh fertig geworden bist.

Wenn du diese Woche startest, hast du Puffer. Wenn du im Juni startest, hast du keinen.


Week-by-week migration roadmap from Shopify Scripts to Functions

Häufig gestellte Fragen

Brauche ich Shopify Plus, um Functions zu nutzen?

Benutzerdefinierte Functions erfordern Shopify Plus, aber Functions aus öffentlichen Apps funktionieren in jedem Plan. Wenn du nicht auf Plus bist, hast du zwei Wege: Installiere eine öffentliche App aus dem Shopify App Store, die die Function für dich liefert, oder upgrade auf Plus, um deine eigenen benutzerdefinierten Functions zu schreiben. Die meisten großen Händler, die Scripts hatten, hatten ohnehin bereits Plus, also ändert sich praktisch selten etwas.

Kann ich Functions in TypeScript schreiben?

Ja — TypeScript wird vollständig unterstützt und die CLI scaffoldet es für dich. Wenn du shopify app generate extension ausführst und „JavaScript“ auswählst, enthält das generierte Projekt Typdeklarationen aus import("../generated/api"). Du kannst Dateien in .ts umwandeln und eine tsconfig.json hinzufügen, wenn du möchtest. Die kompilierte Ausgabe (WASM) ist unabhängig von der Quellsprache identisch.

Wie schnell sind Functions im Vergleich zu Scripts?

Functions werden typischerweise in unter 5 ms ausgeführt — deutlich schneller als Ruby-Scripts. Da sie zu WebAssembly kompiliert und in einer schlanken Runtime ausgeführt werden, setzt Shopify ein Ausführungsbudget von 5 ms durch. Wenn deine Function es überschreitet, wird die Operation verworfen und deine Function gibt keine Operationen zurück. In der Praxis benötigt eine gut geschriebene Function 1–2 ms. Die Performance-Obergrenze ist deutlich höher als bei Scripts.

Kann eine Function eine externe API aufrufen?

Nein — Functions können keine Netzwerkrequests ausführen. Sie sind reine Berechnung: Eingabedaten aus dem Warenkorb → Ausgabe von Operationen. Wenn du externe Daten brauchst (CRM-Lookup, Echtzeit-Bestandsprüfung), musst du die Daten entweder im Voraus in Metafeldern speichern oder eine andere Oberfläche verwenden (App Proxy, Webhooks, Cart Transform mit Backend-Lookup). Das ist der häufigste Grund, warum Teams neu entwerfen statt nur portieren müssen.

Was ist der Unterschied zwischen Cart Transform und Discounts?

Discounts ändern Preise; Cart Transform ändert den Inhalt des Warenkorbs. Verwende die Discounts API für 10 % Rabatt, kostenlosen Versand oder BOGO. Verwende Cart Transform, um zwei Produkte zu einem Line Item zu bündeln oder eine Variante in mehrere aufzusplitten. Viele alte Scripts vermischten beides — trenne es bei der Migration in zwei Functions.

Wie teste ich eine Function lokal ohne Development Store?

Du kannst Unit-Tests mit cargo test (Rust) oder npm test (JS) ausführen, aber vollständige Integrationstests erfordern einen Development Store. Die CLI bietet shopify app function run, womit du deine Function gegen eine Beispiel-Eingabedatei ausführst — nützlich für schnelles Iterieren. Aber um das Checkout-Verhalten end-to-end zu bestätigen, brauchst du einen echten Store mit einem echten Warenkorb.

Kann ich mehrere Functions desselben Typs haben?

Ja — Shopify unterstützt mehrere Functions pro Ziel, und sie werden in deterministischer Reihenfolge ausgeführt. Bei Rabatten wird die Reihenfolge durch Shopifys Regeln zum Stacking von Rabatten bestimmt. Bei Delivery- und Payment-Customizations kannst du Functions aneinanderreihen, aber jede Ausgabe speist die nächste. Die meisten Teams verwenden aus Einfachheitsgründen eine Function pro Typ.

Was passiert mit meinem Script, nachdem ich die Function deployed habe?

Beide laufen parallel, bis du das Script in Apps → Script Editor unveröffentlichst. Das ist beabsichtigt — so erhältst du das Testfenster für den Parallelbetrieb. Nachdem du bestätigt hast, dass die Function funktioniert, veröffentliche das Script manuell nicht mehr. Nach dem 30. Juni 2026 stoppen alle Scripts die Ausführung, unabhängig davon, ob du sie unveröffentlicht hast oder nicht.

Wird die Migration mein SEO oder mein Theme beeinflussen?

Nein — Functions laufen serverseitig im Checkout und berühren weder dein Theme noch deine Produktseiten. Sie ändern nur Rabatte, Versandoptionen und Zahlungsmethoden im Checkout. Dein Storefront, deine Produktvorlagen und dein SEO bleiben völlig unberührt.

Wie migriere ich ein Script, das Input.line_items mit benutzerdefinierten Properties verwendet?

Benutzerdefinierte Properties sind über das attribute-Feld auf den Cart-Lines in der GraphQL-Eingabe zugänglich. Füge attribute(key: "your-key") { value } innerhalb der lines-Auswahl hinzu. Die Function liest es genauso, wie Scripts Line-Item-Properties lesen — nur über GraphQL statt über Ruby-Methodenaufrufe.

Was ist mit Analytics und Order-Tags? Können Functions Daten schreiben?

Functions können keine Order-Tags schreiben oder Webhooks selbst auslösen — sie geben nur Operationen für den aktuellen Warenkorb zurück. Für Tagging oder nachgelagerte Workflows verwende Shopify Flow, ausgelöst durch das Ereignis der Auftragserstellung. Viele Händler kombinieren eine Function (für den Rabatt) mit einem Flow (um die Bestellung mit „VOLUME-DISCOUNT-APPLIED“ zu taggen).

Gibt es eine öffentliche App, die ich installieren kann, statt eine benutzerdefinierte Function zu bauen?

Ja — im Shopify App Store gibt es Dutzende Apps, die Functions für gängige Anwendungsfälle verpacken. Suche nach „discount function“, „delivery customization“ oder „payment customization“. Für einfache Anwendungsfälle (Volumenrabatte, Zahlungsmethoden nach Tag ausblenden, kostenloser Versand über X) kann eine vorhandene App dir Tage an Entwicklungsarbeit sparen. Reserviere benutzerdefinierte Functions für Logik, die wirklich einzigartig für dein Geschäft ist.

Was passiert, wenn ich die Frist am 30. Juni verpasse?

Das Script stoppt die Ausführung — es gibt keinen Fallback, keine Schonfrist und keine Verlängerung. Was auch immer das Script getan hat (der Rabatt, der ausgeblendete Versandtarif, die blockierte Zahlungsmethode), fällt um Mitternacht UTC am 1. Juli auf das Standardverhalten zurück. Wenn dein Geschäft von dieser Logik abhängt, plane, deutlich vor diesem Datum live zu sein. Die Migration dauert länger, als die meisten Teams schätzen, vor allem mit Paritätstests.

Kann ich die Script-Editor-App vollständig löschen?

Du kannst sie nach dem 30. Juni 2026 deinstallieren, aber Shopify wird sie wahrscheinlich automatisch entfernen. Sobald Scripts nicht mehr ausgeführt werden, erfüllt der Editor keinen Zweck mehr. Du kannst außerdem jetzt alle Scripts unveröffentlichen und die App sofort deinstallieren, wenn du die Migration abgeschlossen hast — deine Functions sind unabhängig.

Was du diese Woche tun solltest

Lies diesen Artikel nicht nur und schließe den Tab. Tue in den nächsten sieben Tagen diese vier Dinge.

1. Den Customizations Report ziehen. Gehe zu Settings → Checkout → Customizations Report. Exportiere ihn. Das ist dein Migrations-Backlog.

2. Deine Entwicklungsumgebung einrichten. Installiere Node 18+, Shopify CLI und Rust (falls relevant). Bestätige, dass shopify version funktioniert. Gesamtzeit: 30 Minuten.

3. Eine winzige Function scaffolden und in einen Development Store deployen. Wähle das einfachste Script, das du hast — meist eine Regel zum Ausblenden von Zahlungen. Migriere es end-to-end. Auch wenn es nie in Produktion geht, hast du damit den Toolchain-Stack validiert.

4. Kalenderzeit für die nächsten acht Wochen blocken. Migrationen passieren nicht zwischen zwei Sprints in Restmomenten. Blocke einen wiederkehrenden Slot — zum Beispiel jeden Dienstag- und Donnerstagnachmittag — und behandle ihn wie ein Release.

Aus den Teams, die wir migrieren gesehen haben, ist das Muster immer gleich: zwei Wochen Stillstand, drei Wochen eigentliche Arbeit, eine Woche Aufräumen. Das sind sechs Wochen. Du hast zehn. Den Puffer gibt es — verbrenne ihn in Code Review und QA, nicht im Aufschieben des Starts.

Und sobald deine Checkout-Logik sortiert ist, ist der nächste Punkt, den die meisten Teams angehen, Post-Purchase — Adressänderungen, Umtausch, Rabatt-Ergänzungen nachdem die Bestellung aufgegeben wurde. Wenn das auf deiner Roadmap steht (und das sollte es, egal ob du ein stark frequentierter Plus-Betreiber oder ein CX-orientierter Advanced-Store bist), Revize ist im Shopify App Store und arbeitet mit jeder Function zusammen, die du hier bauen wirst.

Ressourcen

Verwandte Artikel

Es ist der 16. April 2026. Gestern — der 15. April — hat Shopify den Script Editor endgültig gesperrt. Du kannst kein neues Script mehr erstellen oder veröffentlichen. Die Abschaltung der Ausführung erfolgt in 75 Tagen, am 30. Juni 2026.

Wenn du ein Shopify-Plus-Entwickler bist — oder die Agentur, die einen Plus-Store betreut — und diese Migration seit zwölf Monaten auf den „nächsten Sprint“ verschoben hast, hast du ein Problem. Kein „kann man später beheben“-Problem. Ein „dein Checkout bricht am 1. Juli um Mitternacht zusammen“-Problem. Die meisten Plus-Stores haben im Laufe der Jahre 5 bis 20 Scripts angesammelt, von denen jedes unauffällig eine Rabattregel, ein Ausblenden von Versandarten oder eine Zahlungssperre antreibt, an die sich niemand mehr erinnert.

Dieser Leitfaden ist das technische Migrationshandbuch, von dem wir uns im Januar gewünscht hätten, dass es existiert. Er deckt den eigentlichen Code ab — nicht nur die Strategie. Bis du fertig gelesen hast, weißt du, wie du mit der Shopify CLI eine Function scaffoldest, die Rust- oder JavaScript-Logik für Rabatte, Versandanpassungen und Zahlungsanpassungen schreibst, sie sicher gegen eine markierte Teilmenge deiner Kunden testest und sie produktiv ausrollst, ohne deinen bestehenden Checkout zu beschädigen.

Hol die Scripts aus deinem Store heraus und die Functions hinein.


Developer migrating Shopify Scripts to Shopify Functions modules

Kurzantwort: Scripts → Functions in 60 Sekunden

Die Migration in einem Absatz: Shopify Scripts (Ruby-Code im Script Editor, nur für Plus) werden durch Shopify Functions ersetzt (WebAssembly-Module, geschrieben in Rust oder JavaScript, für alle Pläne verfügbar). Du scaffoldest eine Function mit shopify app generate extension, schreibst eine run.graphql-Abfrage, die die benötigten Warenkorbdaten abruft, schreibst eine run.rs- oder run.js-Datei, die Operationen zurückgibt (Rabatte, ausgeblendete Versandarten usw.), deployest dann mit shopify app deploy und aktivierst sie über den Admin oder eine GraphQL-Mutation. Functions laufen als kompiliertes WASM mit unter 5 ms Latenz, funktionieren in jedem Plan und sind der einzige Anpassungsweg, den Shopify künftig unterstützt.

Was sich am 30. Juni tatsächlich ändert

Bevor wir irgendeinen Code anfassen, sollten wir die Daten richtig einordnen. Es gibt zwei davon, und beide sind wichtig.

Datum

Was passiert

Deine Aktion

15. April 2026 (vorbei)

Script Editor nur noch lesbar. Keine neuen Scripts. Keine Änderungen an bestehenden Scripts.

Bestehende Scripts werden weiterhin ausgeführt. Jetzt migrieren oder deine Logik einfrieren.

30. Juni 2026

Alle Shopify Scripts hören auf zu laufen. Punkt.

Dein Ersatz durch eine Function muss vor diesem Datum live sein.

Die Migration ist binär. Entweder ist deine Function bis zum 30. Juni bereitgestellt und dein Checkout funktioniert weiter, oder sie ist es nicht — und jeder betroffene Warenkorb fällt stillschweigend auf Standardpreise, Standard-Versandtarife und alle aktivierten Zahlungsmethoden zurück. Es gibt keine Teilpunkte. Das Script läuft entweder oder eben nicht, und nach dem 30. Juni läuft es nicht mehr.

Tipp: Öffne Settings → Checkout → Customizations Report in deinem Shopify-Admin. Dort sind alle aktiven Scripts in deinem Store aufgeführt, was sie tun und welcher Function-Typ als Ersatz empfohlen wird. Fang dort an.

Functions vs. Scripts: Was sich tatsächlich geändert hat

Dimension

Shopify Scripts (veraltet)

Shopify Functions (Ersatz)

Sprache

Ruby DSL (Shopify-spezifisch)

Rust, JavaScript, TypeScript

Runtime

Sandboxed Ruby auf Shopify-Infrastruktur

WebAssembly (WASM) — Ausführung unter 5 ms

Plan-Verfügbarkeit

Nur Plus

Alle Pläne (benutzerdefinierte Apps erfordern Plus; öffentliche Apps sind offen)

Editor

Script Editor im Admin

Lokale IDE + Shopify CLI

Versionierung

Keine — Live-Änderungen

Git-freundlich — vollständige Versionskontrolle

Testen

Manuell im Checkout

Lokale Entwicklung mit shopify app dev, Preview-Links

Bereitstellung

Im Admin auf „Speichern“ klicken

shopify app deploy im Terminal

Ziele

Line Items, Versand, Zahlungen

Rabatte, Cart Transform, Validation, Delivery Customization, Payment Customization, Order Routing, Fulfillment Constraints, mehr

Der architektonische Wandel ist wichtig. Scripts waren „Ruby in einem Textfeld anpassen“. Functions sind „eine echte App schreiben, per Versionskontrolle verwalten, lokal testen und über eine echte CI-Pipeline bereitstellen“. Das ist ein steilerer Einstieg. Es ist auch die letzte Migration, die du in absehbarer Zeit für Checkout-Logik machst — Functions sind Shopifys langfristiges Bekenntnis und nicht nur ein Provisorium wie es Scripts letztlich waren.

Deine Scripts dem richtigen Function-Typ zuordnen

Jedes Script, das du heute hast, lässt sich genau einer Function-API zuordnen. Hier ist die Lookup-Tabelle, die du dir an den Monitor heften solltest.

Alter Script-Typ

Was es tat

Neue Function-API

Function-Ziel

Line Item Script

Rabatte auf bestimmte Produkte / Kunden / Warenkorb-Bedingungen anwenden

Cart & Checkout Discounts API

cart.lines.discounts.generate.run

Shipping Script (Rabatt)

Kostenloser / vergünstigter Versand basierend auf Warenkorbregeln

Cart & Checkout Discounts API

cart.delivery-options.discounts.generate.run

Shipping Script (ausblenden / umbenennen / umsortieren)

Einen Versandtarif über $X ausblenden, „Standard“ in „Kostenlos ab $50“ umbenennen

Delivery Customization API

cart.delivery-options.transform.run

Payment Script

PayPal für B2B ausblenden, Nachnahme über $500 ausblenden, Zahlungsmethoden umsortieren

Payment Customization API

cart.payment-methods.transform.run

Cart-modifying Script (selten)

Produkte bündeln, Line Items austauschen

Cart Transform API

cart.transform.run

Checkout blockierendes Script

Warenkorb ablehnen, wenn die SKU-Mischung ungültig ist

Cart & Checkout Validation API

cart.validations.generate.run

Wenn du zehn Scripts hast, wirst du wahrscheinlich drei bis fünf Functions bauen — mehrere Scripts lassen sich oft in einer Function mit saubererer Verzweigungslogik zusammenführen.


Shopify Functions unifying discounts, delivery, and payment customizations

Voraussetzung: Lokale Entwicklungsumgebung einrichten

Bevor du irgendeine Function scaffoldest, brauchst du drei Dinge lokal installiert. Führe diese Prüfungen in deinem Terminal aus.

1. Node.js 18+

node --version
# Must be >= 18.0.0

Wenn älter, installiere es über nvm oder lade es von nodejs.org herunter.

2. Shopify CLI 3+

npm install -g @shopify/cli@latest
shopify version
# Should output 3.x or higher

3. Rust-Toolchain (nur wenn du Functions in Rust schreiben willst)

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add wasm32-wasip1
cargo --version

JavaScript-Functions brauchen kein Rust. Wähle für dein Team eine Sprache und bleib dabei — beide zu mischen erhöht den Wartungsaufwand.

4. Einen Development Store

Melde dich entweder im Partner-Dashboard an und erstelle einen neuen Development Store oder verwende einen vorhandenen. Du wirst Functions zunächst in diesen Store deployen, bevor du sie in die Produktion überführst.

Deine erste Function scaffolden

Die CLI erledigt den Großteil des Boilerplates. In jedem Verzeichnis:

# Create a new Shopify app (skip if you already have one)
shopify app init my-checkout-functions
cd my-checkout-functions

# Generate a Function extension
shopify app generate extension

Die CLI führt dich durch die Abfragen. Für eine Discount-Function würdest du wählen:

  • Typ: Function

  • Template: discount (oder cart_checkout_validation, delivery_customization, payment_customization usw.)

  • Sprache: Rust oder JavaScript

  • Name: etwas wie volume-discount-fn

Dadurch wird extensions/volume-discount-fn/ mit Folgendem erstellt:

extensions/volume-discount-fn/
├── shopify.extension.toml      # Function config targets, build, version
├── src/
├── cart_lines_discounts_generate_run.graphql   # Input query
└── cart_lines_discounts_generate_run.rs        # Function logic
├── Cargo.toml                  # Rust dependencies (Rust only)
└── README.md

Die drei Dateien, die du ständig bearbeiten wirst, sind die .toml (Konfiguration), die .graphql (Eingabe) und die .rs / .js (Logik). Das ist alles.

Tutorial 1: Ersetzen eines Line Item Scripts (Volumenrabatt)

Angenommen, dein altes Script gab 10 % Rabatt auf den Warenkorbzwischensumme, sobald der Warenkorb 5+ Einheiten aus einer bestimmten Kollektion enthielt. Hier ist das entsprechende Function-Gegenstück.

Schritt 1.1: die Konfiguration (shopify.extension.toml)

api_version = "2026-01"

[[extensions]]
name = "volume-discount-fn"
handle = "volume-discount-fn"
type = "function"

[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/cart_lines_discounts_generate_run.graphql"
export = "cart_lines_discounts_generate_run"

[extensions.build]
command = "cargo build --target=wasm32-wasip1 --release"
path = "target/wasm32-wasip1/release/volume-discount-fn.wasm"
watch = ["src/**/*.rs"]

Schritt 1.2: die Eingabeabfrage (src/cart_lines_discounts_generate_run.graphql)

query Input {
  cart {
    lines {
      id
      quantity
      cost {
        subtotalAmount {
          amount
        }
      }
      merchandise {
        ... on ProductVariant {
          product {
            inAnyCollection(ids: ["gid://shopify/Collection/123456789"])
          }
        }
      }
    }
  }
  discount {
    discountClasses
  }
}

Tipp: Functions sehen nur die Daten, die du abfragst. Halte GraphQL minimal — jedes Feld, das du weglässt, bedeutet eine schnellere und günstigere Ausführung.

Schritt 1.3: die Logik (src/cart_lines_discounts_generate_run.rs)

use super::schema;
use shopify_function::prelude::*;
use shopify_function::Result;

#[shopify_function]
fn cart_lines_discounts_generate_run(
    input: schema::cart_lines_discounts_generate_run::Input,
) -> Result<schema::CartLinesDiscountsGenerateRunResult> {
    // Bail if discount class doesn't match
    let has_order_discount = input
        .discount()
        .discount_classes()
        .contains(&schema::DiscountClass::Order);

    if !has_order_discount {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Sum quantities of items in the target collection
    let qualifying_qty: i64 = input
        .cart()
        .lines()
        .iter()
        .filter(|line| {
            if let schema::Merchandise::ProductVariant(v) = line.merchandise() {
                *v.product().in_any_collection()
            } else {
                false
            }
        })
        .map(|line| *line.quantity())
        .sum();

    if qualifying_qty < 5 {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Apply 10% off the order subtotal
    Ok(schema::CartLinesDiscountsGenerateRunResult {
        operations: vec![schema::CartOperation::OrderDiscountsAdd(
            schema::OrderDiscountsAddOperation {
                selection_strategy: schema::OrderDiscountSelectionStrategy::First,
                candidates: vec![schema::OrderDiscountCandidate {
                    targets: vec![schema::OrderDiscountCandidateTarget::OrderSubtotal(
                        schema::OrderSubtotalTarget {
                            excluded_cart_line_ids: vec![],
                        },
                    )],
                    message: Some("Volume discount: 10% off".to_string()),
                    value: schema::OrderDiscountCandidateValue::Percentage(
                        schema::Percentage { value: Decimal(10.0) }
                    ),
                    conditions: None,
                    associated_discount_code: None,
                }],
            },
        )],
    })
}

Schritt 1.4: Testen, deployen, aktivieren

# Local development with hot reload
shopify app dev

# When ready, deploy
shopify app deploy

# In the GraphiQL panel that opens (press `g` in the dev terminal),
# create the automatic discount that uses your Function:
mutation {
  discountAutomaticAppCreate(
    automaticAppDiscount: {
      title: "Volume Discount (5+ collection items)"
      functionHandle: "volume-discount-fn"
      discountClasses: [ORDER]
      startsAt: "2026-04-16T00:00:00Z"
    }
  ) {
    automaticAppDiscount { discountId }
    userErrors { field message }
  }
}

Das war's. Die Function ist live, versionskontrolliert und ersetzt das alte Script vollständig.

Tutorial 2: Ersetzen eines Shipping Scripts (Methode oberhalb eines Warenkorb-Schwellenwerts ausblenden)

Ein häufiges Script: „Expressversand ausblenden, wenn die Warenkorb-Zwischensumme über $500 liegt, um teuren Overnight-Versand bei großen Bestellungen zu vermeiden.“ Hier ist die Version als Delivery Customization Function.

Schritt 2.1: Scaffolden

shopify app generate extension --template delivery_customization --name hide-express-fn

Schritt 2.2: Eingabeabfrage (src/run.graphql)

query Input {
  cart {
    cost {
      subtotalAmount {
        amount
      }
    }
    deliveryGroups {
      deliveryOptions {
        handle
        title
      }
    }
  }
}

Schritt 2.3: Logik (src/run.js — JavaScript-Variante)

// @ts-check
/**
 * @typedef {import("../generated/api").RunInput} RunInput
 * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult
 */

const NO_CHANGES = { operations: [] };
const THRESHOLD = 500.0;
const HIDE_TITLES = ["Express", "Overnight"];

/**
 * @param {RunInput} input
 * @returns {FunctionRunResult}
 */
export function run(input) {
  const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount);
  if (subtotal < THRESHOLD) return NO_CHANGES;

  const operations = input.cart.deliveryGroups.flatMap((group) =>
    group.deliveryOptions
      .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t)))
      .map((opt) => ({
        hide: { deliveryOptionHandle: opt.handle },
      }))
  );

  return { operations };
}

Schritt 2.4: Über den Admin aktivieren (kein GraphQL nötig)

Delivery Customizations haben eine integrierte Admin-Oberfläche. Nach shopify app deploy:

  1. Gehe zu Settings → Shipping and delivery

  2. Scrolle zum Abschnitt Customizations unten auf der Seite

  3. Klicke auf Add customization → wähle deine Function aus

  4. Speichern

Die Ausblendungsregel ist in der Produktion live. Keine Mutation erforderlich.


Shopify delivery customization Function hiding shipping option at checkout

Tutorial 3: Ersetzen eines Payment Scripts (Nachnahme für B2B ausblenden)

Altes Script: „Nachnahme für jeden Kunden mit dem Tag 'B2B' ausblenden.“ Hier ist die Version für Payment Customization.

Schritt 3.1: Scaffolden

shopify app generate extension --template payment_customization --name hide-cod-b2b-fn

Schritt 3.2: Eingabeabfrage

query Input {
  cart {
    buyerIdentity {
      customer {
        hasTags(tags: [{ tag: "B2B" }]) {
          tag
          hasTag
        }
      }
    }
  }
  paymentMethods {
    id
    name
  }
}

Schritt 3.3: Logik (src/run.js)

const NO_CHANGES = { operations: [] };

export function run(input) {
  const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0];
  const isB2B = tagCheck?.hasTag === true;
  if (!isB2B) return NO_CHANGES;

  const codMethod = input.paymentMethods.find((pm) =>
    pm.name.toLowerCase().includes("cash on delivery")
  );
  if (!codMethod) return NO_CHANGES;

  return {
    operations: [{ hide: { paymentMethodId: codMethod.id } }],
  };
}

Schritt 3.4: Aktivieren

Payment Customizations haben ebenfalls eine Admin-Oberfläche unter Settings → Payments → Customizations. Derselbe Ablauf wie beim Versand — Function auswählen, speichern, fertig.

Weil du das hier liest — ein Wort zu Post-Purchase

Eine kurze Offenlegung, da dies der Revize-Blog ist. Revize kümmert sich um die Dinge, die Functions nicht anfassen können — sobald eine Bestellung aufgegeben wurde, wollen Kunden einen Artikel hinzufügen, eine Größe tauschen, die Lieferadresse korrigieren oder einen vergessenen Rabatt anwenden. Functions sitzen im Checkout. Revize sitzt danach. Functions entscheiden, was im Warenkorb erlaubt ist; Revize gibt deinen Kunden und deinem Support-Team die Möglichkeit, die Bestellung danach zu bearbeiten, ohne einen Refund-und-Neuaufbau-Zyklus. Das ist für zwei Arten von Stores wichtig: für jene mit so viel Bestellvolumen, dass manuelle Bearbeitung zusammenbricht (Plus-Betreiber natürlich, aber auch hochfrequentierte Advanced-Stores), und für jene, deren gesamte Marke auf Kundenerlebnis basiert — wo eine „Entschuldigung, das können wir nicht ändern“-E-Mail Wiederkäufe killt.

Wenn dein Migrationsplan Scripts → Functions abdeckt, du aber Post-Purchase-Bestelländerungen noch nie sauber sortiert hast, stößt du in etwa drei Wochen an die nächste „Warum ist das so schwer?“-Wand. Der Bestellverwaltungs-Leitfaden, den wir gerade veröffentlicht haben zeigt den vollständigen Post-Checkout-Plan.

Zurück zur Migration.

Teststrategie: Das Muster mit markierten Kunden

Functions haben keinen „Entwurfsmodus“, den du im Admin umschalten kannst. Das professionelle Muster ist, die neue Function an einem Kunden-Tag zu koppeln, das alte Script und die neue Function parallel laufen zu lassen, zu prüfen, ob sie für markierte Nutzer identische Ergebnisse liefern, und dann den Schalter umzulegen.

Schritt 1: Testnutzer taggen

Füge unter Kunden zwei oder drei internen Konten den Tag FN-TESTER hinzu.

Schritt 2: Die Function an das Vorhandensein des Tags verzweigen

// At the top of your run function
let is_tester = input
    .cart()
    .buyer_identity()
    .and_then(|bi| bi.customer())
    .map(|c| c.has_any_tag())
    .unwrap_or(&false);

if !*is_tester {
    return Ok(default_result);  // Fall through to existing Script
}

// New Function logic only runs for tagged users

Schritt 3: hasAnyTag zu deiner Eingabeabfrage hinzufügen

cart {
  buyerIdentity {
    customer {
      hasAnyTag(tags: ["FN-TESTER"])
    }
  }
}

Schritt 4: Im Checkout verifizieren

Melde dich als markierter Nutzer an, gehe durch den Checkout und bestätige, dass die Function ausgelöst wird. Melde dich als unmarkierter Nutzer an und bestätige, dass das alte Script weiterhin läuft. Wenn die Parität einige Tage lang hält, entferne die Tag-Prüfung und lass die Function für alle laufen.

Schritt 5: Das alte Script unveröffentlichen

Gehe zu Apps → Script Editor → [Dein Script] → Unpublish. Sobald es unveröffentlicht ist, ist die Function die einzige Quelle der Wahrheit.

Ein Bereitstellungs-Workflow, der wirklich skaliert

Deploye nicht für immer vom Laptop eines Entwicklers aus. Sobald du ein oder zwei Scripts migriert hast, richte eine echte CI-Pipeline ein.

Der minimal brauchbare Workflow

# .github/workflows/deploy-functions.yml
name: Deploy Shopify Functions
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - uses: dtolnay/rust-toolchain@stable
        with: { targets: wasm32-wasip1 }
      - run: npm install -g @shopify/cli@latest
      - run: shopify app deploy --force
        env:
          SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}

Generiere das Partner-Token in deinem Partner-Dashboard unter Settings → Tokens. Ab jetzt liefert jeder Merge nach main deine Functions aus. Keine Slack-Threads mehr à la „Hat Mike das deployed?“

Versionierung und Rollback

shopify app deploy erstellt einen versionierten Snapshot. Für ein Rollback:

shopify app versions list
shopify app release --version <previous-version-id

Im Vergleich zu Scripts — wo Rollback bedeutete: „Erinnere dich an den alten Code und füge ihn wieder ein“ — ist das ein Unterschied wie Tag und Nacht.


Shopify Functions deployment pipeline across local staging and production environments

Was die meisten Teams falsch machen

Nachdem wir Plus-Händler im letzten Jahr durch diese Migration begleitet haben, tauchen immer wieder dieselben fünf Fehler auf.

1. Functions als 1:1-Port eines Scripts zu behandeln. Das sind sie nicht. Eine einzige Function kann drei Scripts mit saubererer Verzweigungslogik ersetzen. Prüfe deine Scripts als System, bevor du sie neu schreibst.

2. Die Leseberechtigungen zu vergessen. Viele Functions benötigen read_customers, read_orders oder write_discounts. Füge sie in shopify.app.toml unter scopes hinzu und autorisiere die App neu, sonst liefert deine Eingabeabfrage null zurück.

3. Functions mit nicht getaggten Kunden ohne Paritätstest laufen zu lassen. Selbst wenn dein Code richtig aussieht, werden Randfälle (leerer Warenkorb, Geschenkkarten, Store Credit, B2B-Entwürfe) Probleme aufdecken. Eine tag-gesteuerte Ausrollung kostet dich zwei Tage und erspart dir einen P1-Ausfall.

4. Den Customizations Report zu überspringen. Er ist das beste Inventar dessen, was tatsächlich läuft. Migriere nicht aus dem Gedächtnis — migriere aus dem Report.

5. Kollektion-IDs und Kundentags hart zu verdrahten. Verwende Function-Konfiguration über Metafelder, wenn du vom Händler anpassbare Werte brauchst. Die CLI kann Metafeld-gestützte Konfiguration scaffolden — siehe Shopifys Doku zur Function-Konfiguration.

Migrations-Checkliste für die nächsten 75 Tage

Ein realistischer Wochen-für-Wochen-Plan, um bis zum 30. Juni ruhig ans Ziel zu kommen.

Woche

Aktion

Woche 1 (diese Woche)

Ziehe den Customizations Report. Erfasse jedes Script. Entscheide: Function vs. öffentliche App vs. löschen.

Wochen 2–3

Lokale Entwicklungsumgebung einrichten. Die erste Function scaffolden. Das einfachste Script migrieren (meist eine Regel zum Ausblenden von Zahlungen).

Wochen 4–6

Discount-Scripts migrieren. Diese dauern am längsten, weil die Discounts API am umfangreichsten ist. Gründlich per Tag testen.

Wochen 7–8

Shipping-/Delivery-Scripts migrieren. Delivery Customizations über den Admin aktivieren.

Wochen 9–10

CI-Pipeline einrichten. Alle Bereitstellungen von Entwickler-Laptops wegziehen.

Woche 11 (Mitte Juni)

Abschließende Paritätsprüfung. Alle Scripts unveröffentlichen. Den Store zwei Wochen lang nur auf Functions laufen lassen.

30. Juni

Der Stichtag ist da. Nichts bricht, weil du früh fertig geworden bist.

Wenn du diese Woche startest, hast du Puffer. Wenn du im Juni startest, hast du keinen.


Week-by-week migration roadmap from Shopify Scripts to Functions

Häufig gestellte Fragen

Brauche ich Shopify Plus, um Functions zu nutzen?

Benutzerdefinierte Functions erfordern Shopify Plus, aber Functions aus öffentlichen Apps funktionieren in jedem Plan. Wenn du nicht auf Plus bist, hast du zwei Wege: Installiere eine öffentliche App aus dem Shopify App Store, die die Function für dich liefert, oder upgrade auf Plus, um deine eigenen benutzerdefinierten Functions zu schreiben. Die meisten großen Händler, die Scripts hatten, hatten ohnehin bereits Plus, also ändert sich praktisch selten etwas.

Kann ich Functions in TypeScript schreiben?

Ja — TypeScript wird vollständig unterstützt und die CLI scaffoldet es für dich. Wenn du shopify app generate extension ausführst und „JavaScript“ auswählst, enthält das generierte Projekt Typdeklarationen aus import("../generated/api"). Du kannst Dateien in .ts umwandeln und eine tsconfig.json hinzufügen, wenn du möchtest. Die kompilierte Ausgabe (WASM) ist unabhängig von der Quellsprache identisch.

Wie schnell sind Functions im Vergleich zu Scripts?

Functions werden typischerweise in unter 5 ms ausgeführt — deutlich schneller als Ruby-Scripts. Da sie zu WebAssembly kompiliert und in einer schlanken Runtime ausgeführt werden, setzt Shopify ein Ausführungsbudget von 5 ms durch. Wenn deine Function es überschreitet, wird die Operation verworfen und deine Function gibt keine Operationen zurück. In der Praxis benötigt eine gut geschriebene Function 1–2 ms. Die Performance-Obergrenze ist deutlich höher als bei Scripts.

Kann eine Function eine externe API aufrufen?

Nein — Functions können keine Netzwerkrequests ausführen. Sie sind reine Berechnung: Eingabedaten aus dem Warenkorb → Ausgabe von Operationen. Wenn du externe Daten brauchst (CRM-Lookup, Echtzeit-Bestandsprüfung), musst du die Daten entweder im Voraus in Metafeldern speichern oder eine andere Oberfläche verwenden (App Proxy, Webhooks, Cart Transform mit Backend-Lookup). Das ist der häufigste Grund, warum Teams neu entwerfen statt nur portieren müssen.

Was ist der Unterschied zwischen Cart Transform und Discounts?

Discounts ändern Preise; Cart Transform ändert den Inhalt des Warenkorbs. Verwende die Discounts API für 10 % Rabatt, kostenlosen Versand oder BOGO. Verwende Cart Transform, um zwei Produkte zu einem Line Item zu bündeln oder eine Variante in mehrere aufzusplitten. Viele alte Scripts vermischten beides — trenne es bei der Migration in zwei Functions.

Wie teste ich eine Function lokal ohne Development Store?

Du kannst Unit-Tests mit cargo test (Rust) oder npm test (JS) ausführen, aber vollständige Integrationstests erfordern einen Development Store. Die CLI bietet shopify app function run, womit du deine Function gegen eine Beispiel-Eingabedatei ausführst — nützlich für schnelles Iterieren. Aber um das Checkout-Verhalten end-to-end zu bestätigen, brauchst du einen echten Store mit einem echten Warenkorb.

Kann ich mehrere Functions desselben Typs haben?

Ja — Shopify unterstützt mehrere Functions pro Ziel, und sie werden in deterministischer Reihenfolge ausgeführt. Bei Rabatten wird die Reihenfolge durch Shopifys Regeln zum Stacking von Rabatten bestimmt. Bei Delivery- und Payment-Customizations kannst du Functions aneinanderreihen, aber jede Ausgabe speist die nächste. Die meisten Teams verwenden aus Einfachheitsgründen eine Function pro Typ.

Was passiert mit meinem Script, nachdem ich die Function deployed habe?

Beide laufen parallel, bis du das Script in Apps → Script Editor unveröffentlichst. Das ist beabsichtigt — so erhältst du das Testfenster für den Parallelbetrieb. Nachdem du bestätigt hast, dass die Function funktioniert, veröffentliche das Script manuell nicht mehr. Nach dem 30. Juni 2026 stoppen alle Scripts die Ausführung, unabhängig davon, ob du sie unveröffentlicht hast oder nicht.

Wird die Migration mein SEO oder mein Theme beeinflussen?

Nein — Functions laufen serverseitig im Checkout und berühren weder dein Theme noch deine Produktseiten. Sie ändern nur Rabatte, Versandoptionen und Zahlungsmethoden im Checkout. Dein Storefront, deine Produktvorlagen und dein SEO bleiben völlig unberührt.

Wie migriere ich ein Script, das Input.line_items mit benutzerdefinierten Properties verwendet?

Benutzerdefinierte Properties sind über das attribute-Feld auf den Cart-Lines in der GraphQL-Eingabe zugänglich. Füge attribute(key: "your-key") { value } innerhalb der lines-Auswahl hinzu. Die Function liest es genauso, wie Scripts Line-Item-Properties lesen — nur über GraphQL statt über Ruby-Methodenaufrufe.

Was ist mit Analytics und Order-Tags? Können Functions Daten schreiben?

Functions können keine Order-Tags schreiben oder Webhooks selbst auslösen — sie geben nur Operationen für den aktuellen Warenkorb zurück. Für Tagging oder nachgelagerte Workflows verwende Shopify Flow, ausgelöst durch das Ereignis der Auftragserstellung. Viele Händler kombinieren eine Function (für den Rabatt) mit einem Flow (um die Bestellung mit „VOLUME-DISCOUNT-APPLIED“ zu taggen).

Gibt es eine öffentliche App, die ich installieren kann, statt eine benutzerdefinierte Function zu bauen?

Ja — im Shopify App Store gibt es Dutzende Apps, die Functions für gängige Anwendungsfälle verpacken. Suche nach „discount function“, „delivery customization“ oder „payment customization“. Für einfache Anwendungsfälle (Volumenrabatte, Zahlungsmethoden nach Tag ausblenden, kostenloser Versand über X) kann eine vorhandene App dir Tage an Entwicklungsarbeit sparen. Reserviere benutzerdefinierte Functions für Logik, die wirklich einzigartig für dein Geschäft ist.

Was passiert, wenn ich die Frist am 30. Juni verpasse?

Das Script stoppt die Ausführung — es gibt keinen Fallback, keine Schonfrist und keine Verlängerung. Was auch immer das Script getan hat (der Rabatt, der ausgeblendete Versandtarif, die blockierte Zahlungsmethode), fällt um Mitternacht UTC am 1. Juli auf das Standardverhalten zurück. Wenn dein Geschäft von dieser Logik abhängt, plane, deutlich vor diesem Datum live zu sein. Die Migration dauert länger, als die meisten Teams schätzen, vor allem mit Paritätstests.

Kann ich die Script-Editor-App vollständig löschen?

Du kannst sie nach dem 30. Juni 2026 deinstallieren, aber Shopify wird sie wahrscheinlich automatisch entfernen. Sobald Scripts nicht mehr ausgeführt werden, erfüllt der Editor keinen Zweck mehr. Du kannst außerdem jetzt alle Scripts unveröffentlichen und die App sofort deinstallieren, wenn du die Migration abgeschlossen hast — deine Functions sind unabhängig.

Was du diese Woche tun solltest

Lies diesen Artikel nicht nur und schließe den Tab. Tue in den nächsten sieben Tagen diese vier Dinge.

1. Den Customizations Report ziehen. Gehe zu Settings → Checkout → Customizations Report. Exportiere ihn. Das ist dein Migrations-Backlog.

2. Deine Entwicklungsumgebung einrichten. Installiere Node 18+, Shopify CLI und Rust (falls relevant). Bestätige, dass shopify version funktioniert. Gesamtzeit: 30 Minuten.

3. Eine winzige Function scaffolden und in einen Development Store deployen. Wähle das einfachste Script, das du hast — meist eine Regel zum Ausblenden von Zahlungen. Migriere es end-to-end. Auch wenn es nie in Produktion geht, hast du damit den Toolchain-Stack validiert.

4. Kalenderzeit für die nächsten acht Wochen blocken. Migrationen passieren nicht zwischen zwei Sprints in Restmomenten. Blocke einen wiederkehrenden Slot — zum Beispiel jeden Dienstag- und Donnerstagnachmittag — und behandle ihn wie ein Release.

Aus den Teams, die wir migrieren gesehen haben, ist das Muster immer gleich: zwei Wochen Stillstand, drei Wochen eigentliche Arbeit, eine Woche Aufräumen. Das sind sechs Wochen. Du hast zehn. Den Puffer gibt es — verbrenne ihn in Code Review und QA, nicht im Aufschieben des Starts.

Und sobald deine Checkout-Logik sortiert ist, ist der nächste Punkt, den die meisten Teams angehen, Post-Purchase — Adressänderungen, Umtausch, Rabatt-Ergänzungen nachdem die Bestellung aufgegeben wurde. Wenn das auf deiner Roadmap steht (und das sollte es, egal ob du ein stark frequentierter Plus-Betreiber oder ein CX-orientierter Advanced-Store bist), Revize ist im Shopify App Store und arbeitet mit jeder Function zusammen, die du hier bauen wirst.

Ressourcen

Verwandte Artikel

Überarbeiten Sie Ihren Shopify-Shop und führen Sie mit
Kundenerlebnis

© Copyright 2024, Alle Rechte vorbehalten

Überarbeiten Sie Ihren Shopify-Shop und führen Sie mit
Kundenerlebnis

© Copyright 2024, Alle Rechte vorbehalten

Überarbeiten Sie Ihren Shopify-Shop und führen Sie mit
Kundenerlebnis

© Copyright 2024, Alle Rechte vorbehalten

Überarbeiten Sie Ihren Shopify-Shop und führen Sie mit
Kundenerlebnis

© Copyright 2024, Alle Rechte vorbehalten

The Universal Commerce Protocol UCP Guide How to Start a Shopify Store in 2026 The True Cost of Returns Guide How to Change Shipping Address on Shopify Best Shopify Customer Service Apps 10 Advanced Shopify Flow Workflows How to Add Discount on Shopify After Checkout How to Edit an Order on Shopify Shopify Draft Orders Complete Guide How to Do a Partial Refund on Shopify Shopify Social Login Complete Guide Post Purchase Email Marketing Automating E-commerce with Shopify Flow Customize Shopify Login Redirect Shopify New Customer Accounts Migration Guide How Poor Customer Support Can Sabotage Your Business How Refunds Work on Shopify In-House Warranty Management vs Shopify Apps Shopify Checkout Extensibility 2026: You Missed the Deadline. Now What? How to Let Customers Cancel Orders on Shopify Shopify Legacy Customer Accounts Are Deprecated: What Every Merchant Needs to Do Right Now How to Edit Your Shopify Order Confirmation Email How to Do an Exchange on Shopify How to Sell on ChatGPT with Shopify Agentic Storefronts Shopify Functions Migration Tutorial