Comment migrer les Shopify Scripts vers les Functions : le tutoriel de code complet (édition 2026)

Comment migrer les Shopify Scripts vers les Functions : le tutoriel de code complet (édition 2026)

Comment migrer les Shopify Scripts vers les Functions : le tutoriel de code complet (édition 2026)

Comment migrer les scripts Shopify vers les fonctions : le tutoriel complet du code (édition 2026) — en-tête de l’article de blog Revize

Nous sommes le 16 avril 2026. Hier — le 15 avril — était le jour où Shopify a verrouillé définitivement l’éditeur de Scripts. Vous ne pouvez plus créer ni publier de nouveau Script. L’arrêt d’exécution arrivera dans 75 jours, le 30 juin 2026.

Si vous êtes développeur Shopify Plus — ou l’agence qui gère une boutique Plus — et que vous avez repoussé cette migration à « la prochaine sprint » pendant les douze derniers mois, vous avez un problème. Pas un problème du type « ce serait bien à corriger ». Un problème du type « votre checkout casse à minuit le 1er juillet ». La plupart des boutiques Plus ont accumulé 5 à 20 Scripts au fil des ans, chacun alimentant discrètement une règle de remise, un masquage d’expédition ou une restriction de paiement dont plus personne ne se souvient avoir écrit le code.

Ce guide est le manuel technique de migration que nous aurions voulu avoir en janvier. Il couvre le vrai code — pas seulement la stratégie. Une fois votre lecture terminée, vous saurez comment scaffold une Function avec Shopify CLI, écrire la logique Rust ou JavaScript pour les remises, les personnalisations de livraison et les personnalisations de paiement, la tester prudemment sur un sous-ensemble balisé de vos clients, puis la déployer en production sans casser votre checkout existant.

Retirons les Scripts de votre boutique et mettons-y les Functions.


Developer migrating Shopify Scripts to Shopify Functions modules

Réponse rapide : Scripts → Functions en 60 secondes

La migration en un paragraphe : les Shopify Scripts (code Ruby dans l’éditeur de Scripts, réservé à Plus) sont remplacés par les Shopify Functions (modules WebAssembly écrits en Rust ou en JavaScript, disponibles sur tous les plans). Vous créez une Function avec shopify app generate extension, vous écrivez une requête run.graphql qui récupère les données de panier dont vous avez besoin, vous écrivez un fichier run.rs ou run.js qui renvoie des opérations (remises, méthodes d’expédition masquées, etc.), puis vous déployez avec shopify app deploy et l’activez via l’Admin ou une mutation GraphQL. Les Functions s’exécutent en WASM compilé avec une latence inférieure à 5 ms, fonctionnent sur tous les plans et constituent désormais le seul chemin de personnalisation pris en charge par Shopify.

Ce qui change réellement le 30 juin

Avant de toucher au code, mettons les dates au clair. Il y en a deux, et elles comptent toutes les deux.

Date

Ce qui se passe

Votre action

15 avril 2026 (passé)

L’éditeur de Scripts est en lecture seule. Plus de nouveaux Scripts. Plus de modifications des Scripts existants.

Les Scripts existants s’exécutent encore. Migrez maintenant ou figez votre logique.

30 juin 2026

Tous les Shopify Scripts cessent de s’exécuter. Point final.

Votre remplacement par une Function doit être en ligne avant cette date.

La migration est binaire. Soit votre Function est déployée d’ici le 30 juin et votre checkout continue de fonctionner, soit ce n’est pas le cas — et chaque panier concerné retombe silencieusement sur la tarification standard, les frais de livraison standard et tous les moyens de paiement activés. Il n’y a pas de demi-mesure. Le Script s’exécute ou non, et après le 30 juin, il ne s’exécute plus.

Astuce : Ouvrez Settings → Checkout → Customizations Report dans votre administration Shopify. Cela liste chaque Script actif de votre boutique, ce qu’il fait et le type de remplacement par Function recommandé. Commencez par là.

Functions vs Scripts : ce qui a vraiment changé

Dimension

Shopify Scripts (obsolètes)

Shopify Functions (remplacement)

Langage

DSL Ruby (spécifique à Shopify)

Rust, JavaScript, TypeScript

Runtime

Ruby sandboxé sur l’infrastructure Shopify

WebAssembly (WASM) — exécution sous les 5 ms

Disponibilité selon le plan

Uniquement Plus

Tous les plans (les apps personnalisées nécessitent Plus ; les apps publiques sont ouvertes)

Éditeur

Éditeur de Scripts dans l’admin

IDE local + Shopify CLI

Versioning

Aucun — modifications en direct

Compatible Git — contrôle de version complet

Tests

Manuel dans le checkout

Développement local avec shopify app dev, liens de prévisualisation

Déploiement

Cliquer sur « Enregistrer » dans l’admin

shopify app deploy depuis le terminal

Cibles

Articles, expédition, paiements

Remises, transformation du panier, validation, personnalisation de livraison, personnalisation de paiement, routage des commandes, contraintes de fulfillment, et plus

Le changement architectural est important. Les Scripts, c’était « retoucher du Ruby dans une zone de texte ». Les Functions, c’est « écrire une vraie application, la versionner, la tester localement, la déployer via un vrai pipeline CI ». La courbe d’apprentissage est plus raide. Mais c’est aussi la dernière migration que vous ferez pour la logique de checkout dans un avenir prévisible — les Functions sont l’engagement à long terme de Shopify, pas un palliatif comme l’étaient finalement les Scripts.

Associer vos Scripts au bon type de Function

Chaque Script que vous avez aujourd’hui correspond à une seule API Function. Voici le tableau de correspondance à garder sous les yeux.

Ancien type de Script

Ce qu’il faisait

Nouvelle API Function

Cible de la Function

Line Item Script

Appliquer des remises à des produits / clients / conditions de panier spécifiques

Cart & Checkout Discounts API

cart.lines.discounts.generate.run

Shipping Script (remise)

Livraison gratuite / remisée selon les règles du panier

Cart & Checkout Discounts API

cart.delivery-options.discounts.generate.run

Shipping Script (masquer / renommer / réordonner)

Masquer un tarif de livraison au-dessus de X $, renommer « Standard » en « Gratuit au-delà de 50 $ »

Delivery Customization API

cart.delivery-options.transform.run

Payment Script

Masquer PayPal pour le B2B, masquer le paiement à la livraison au-dessus de 500 $, réordonner les moyens

Payment Customization API

cart.payment-methods.transform.run

Script de modification du panier (rare)

Regrouper des produits, remplacer des line items

Cart Transform API

cart.transform.run

Script de blocage du checkout

Refuser le panier si le mélange de SKU est invalide

Cart & Checkout Validation API

cart.validations.generate.run

Si vous avez dix Scripts, vous construirez probablement trois à cinq Functions — plusieurs Scripts se regroupent souvent en une seule Function avec une logique de branchement plus propre.


Shopify Functions unifying discounts, delivery, and payment customizations

Prérequis : configurer votre environnement de développement local

Avant de scaffold une Function, vous devez installer trois éléments en local. Lancez ces vérifications dans votre terminal.

1. Node.js 18+

node --version
# Doit être >= 18.0.0
node --version
# Doit être >= 18.0.0

Si votre version est plus ancienne, installez-la via nvm ou téléchargez-la depuis nodejs.org.

2. Shopify CLI 3+

npm install -g @shopify/cli@latest
shopify version
# Devrait afficher 3.x ou plus
npm install -g @shopify/cli@latest
shopify version
# Devrait afficher 3.x ou plus

3. Chaîne d’outils Rust (uniquement si vous écrivez vos Functions en Rust)

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

Les Functions JavaScript n’ont pas besoin de Rust. Choisissez un langage pour votre équipe et tenez-vous-y — en utiliser deux ajoute une surcharge de maintenance.

4. Une boutique de développement

Connectez-vous à votre tableau de bord Partner et créez une nouvelle boutique de développement, ou utilisez-en une existante. Vous déploierez les Functions sur cette boutique avant de passer en production.

Scaffolder votre première Function

La CLI génère la majeure partie du boilerplate. Dans n’importe quel répertoire :

# Créez une nouvelle app Shopify (ignorez cette étape si vous en avez déjà une)
shopify app init my-checkout-functions
cd my-checkout-functions

# Générez une extension Function
shopify app generate extension
# Créez une nouvelle app Shopify (ignorez cette étape si vous en avez déjà une)
shopify app init my-checkout-functions
cd my-checkout-functions

# Générez une extension Function
shopify app generate extension

La CLI vous guide à travers les invites. Pour une Function de remise, vous choisiriez :

  • Type : Function

  • Template : discount (ou cart_checkout_validation, delivery_customization, payment_customization, etc.)

  • Langage : Rust ou JavaScript

  • Nom : quelque chose comme volume-discount-fn

Cela crée extensions/volume-discount-fn/ avec :

extensions/volume-discount-fn/
├── shopify.extension.toml      # Configuration de la Function cibles, build, version
├── src/
├── cart_lines_discounts_generate_run.graphql   # Requête d’entrée
└── cart_lines_discounts_generate_run.rs        # Logique de la Function
├── Cargo.toml                  # Dépendances Rust (Rust uniquement)
└── README.md
extensions/volume-discount-fn/
├── shopify.extension.toml      # Configuration de la Function cibles, build, version
├── src/
├── cart_lines_discounts_generate_run.graphql   # Requête d’entrée
└── cart_lines_discounts_generate_run.rs        # Logique de la Function
├── Cargo.toml                  # Dépendances Rust (Rust uniquement)
└── README.md

Les trois fichiers que vous modifierez constamment sont le .toml (configuration), le .graphql (entrée) et le .rs / .js (logique). C’est tout.

Tutoriel 1 : remplacer un Line Item Script (remise sur volume)

Supposons que votre ancien Script accordait 10 % de remise sur le sous-total de la commande lorsque le panier contenait 5 unités ou plus d’une collection spécifique. Voici l’équivalent en Function.

Étape 1.1 : la configuration (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"]

Étape 1.2 : la requête d’entrée (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
  }
}

Astuce : Les Functions ne voient que les données que vous interrogez. Gardez le GraphQL minimal — chaque champ que vous omettez signifie une exécution plus rapide et moins coûteuse.

Étape 1.3 : la logique (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> {
    // Quitter si la classe de remise ne correspond pas
    let has_order_discount = input
        .discount()
        .discount_classes()
        .contains(&schema::DiscountClass::Order);

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

    // Additionner les quantités des articles de la collection cible
    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![] });
    }

    // Appliquer 10 % de remise sur le sous-total de la commande
    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> {
    // Quitter si la classe de remise ne correspond pas
    let has_order_discount = input
        .discount()
        .discount_classes()
        .contains(&schema::DiscountClass::Order);

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

    // Additionner les quantités des articles de la collection cible
    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![] });
    }

    // Appliquer 10 % de remise sur le sous-total de la commande
    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,
                }],
            },
        )],
    })
}

Étape 1.4 : tester, déployer, activer

# Développement local avec rechargement à chaud
shopify app dev

# Une fois prêt, déployez
shopify app deploy

# Dans le panneau GraphiQL qui s’ouvre (appuyez sur `g` dans le terminal de dev),
# créez la remise automatique qui utilise votre Function :
# Développement local avec rechargement à chaud
shopify app dev

# Une fois prêt, déployez
shopify app deploy

# Dans le panneau GraphiQL qui s’ouvre (appuyez sur `g` dans le terminal de dev),
# créez la remise automatique qui utilise votre 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 }
  }
}

C’est tout. La Function est en ligne, versionnée, et remplace entièrement l’ancien Script.

Tutoriel 2 : remplacer un Shipping Script (masquer une méthode au-dessus d’un seuil de panier)

Script courant : « Masquer la livraison Express lorsque le sous-total du panier dépasse 500 $ afin d’éviter une expédition de nuit coûteuse sur les grosses commandes. » Voici la version Function en Delivery Customization.

Étape 2.1 : scaffold

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

Étape 2.2 : requête d’entrée (src/run.graphql)

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

Étape 2.3 : logique (src/run.js — variante JavaScript)

// @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 };
}

Étape 2.4 : activation via l’Admin (aucun GraphQL requis)

Les Delivery Customizations disposent aussi d’une interface d’administration intégrée. Après shopify app deploy :

  1. Allez dans Settings → Shipping and delivery

  2. Faites défiler jusqu’à la section Customizations en bas

  3. Cliquez sur Add customization → sélectionnez votre Function

  4. Enregistrez

La règle de masquage est active en production. Aucune mutation n’est nécessaire.


Shopify delivery customization Function hiding shipping option at checkout

Tutoriel 3 : remplacer un Payment Script (masquer le paiement à la livraison pour le B2B)

Ancien Script : « Masquer le paiement à la livraison pour tout client ayant le tag 'B2B'. » Voici la version Payment Customization.

Étape 3.1 : scaffold

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

Étape 3.2 : requête d’entrée

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
  }
}

Étape 3.3 : logique (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 } }],
  };
}

Étape 3.4 : activation

Les Payment Customizations disposent aussi d’une interface d’administration sous Settings → Payments → Customizations. Même processus que pour la livraison — choisissez votre Function, enregistrez, terminé.

Puisque vous lisez ceci — un mot sur l’après-achat

Petite précision puisque c’est le blog de Revize. Revize gère ce que les Functions ne peuvent pas toucher — une fois qu’une commande est passée, les clients veulent ajouter un article, changer une taille, corriger l’adresse de livraison, appliquer une remise qu’ils ont oubliée. Les Functions vivent au checkout. Revize vit après le checkout. Les Functions décident de ce qui est autorisé dans le panier ; Revize permet à vos clients et à votre équipe support de modifier la commande ensuite sans passer par un cycle remboursement + recréation. Cela compte pour deux types de boutiques : celles qui ont suffisamment de volume de commandes pour que l’édition manuelle s’effondre (les opérateurs Plus, évidemment, mais aussi les boutiques Advanced à fort débit), et celles dont toute la marque repose sur l’expérience client — où un e-mail du type « désolé, nous ne pouvons pas modifier cela » tue les achats répétés.

Si votre plan de migration couvre Scripts → Functions mais que vous n’avez jamais réglé les modifications de commandes après achat, vous allez heurter le prochain mur « pourquoi est-ce si compliqué ? » dans environ trois semaines. Le guide de gestion des commandes que nous venons de publier décrit tout le plan de bataille post-checkout.

Retour à la migration.

Stratégie de test : le modèle du client balisé

Les Functions n’ont pas de « mode brouillon » que vous pouvez activer ou désactiver dans l’admin. La méthode professionnelle consiste à conditionner la nouvelle Function à un tag client, à faire fonctionner en parallèle l’ancien Script et la nouvelle Function, à vérifier qu’ils produisent une sortie identique pour les utilisateurs balisés, puis à basculer.

Étape 1 : taguez vos utilisateurs de test

Dans Customers, ajoutez le tag FN-TESTER à deux ou trois comptes internes.

Étape 2 : branchez la Function sur la présence du tag

// En haut de votre fonction run
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);  // Laisser passer vers le Script existant
}

// La nouvelle logique de la Function ne s’exécute que pour les utilisateurs balisés
// En haut de votre fonction run
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);  // Laisser passer vers le Script existant
}

// La nouvelle logique de la Function ne s’exécute que pour les utilisateurs balisés

Étape 3 : ajoutez hasAnyTag à votre requête d’entrée

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

Étape 4 : vérifiez dans le checkout

Connectez-vous en tant qu’utilisateur balisé, parcourez le checkout, confirmez que la Function se déclenche. Connectez-vous en tant qu’utilisateur non balisé, confirmez que l’ancien Script s’exécute toujours. Quand la parité tient pendant quelques jours, retirez la vérification du tag et laissez la Function s’exécuter pour tout le monde.

Étape 5 : dépubliez l’ancien Script

Allez dans Apps → Script Editor → [Your Script] → Unpublish. Une fois dépublié, la Function devient la seule source de vérité.

Un workflow de déploiement qui passe vraiment à l’échelle

Ne déployez pas éternellement depuis l’ordinateur portable d’un développeur. Une fois un ou deux Scripts migrés, mettez en place un vrai pipeline CI.

Le workflow minimal viable

# .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 }}

Générez le jeton Partner depuis votre tableau de bord Partner sous Settings → Tokens. Désormais, chaque fusion dans main déploie vos Functions. Fini les fils Slack du genre « Mike a-t-il déployé ça ? ».

Versioning et rollback

shopify app deploy crée un instantané versionné. Pour revenir en arrière :

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

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

Comparé aux Scripts — où le rollback voulait dire « se souvenir de l’ancien code et le recoller » — c’est le jour et la nuit.


Shopify Functions deployment pipeline across local staging and production environments

Ce que la plupart des équipes font mal

Après avoir accompagné des marchands Plus dans cette migration au cours de l’année écoulée, on retrouve toujours les cinq mêmes erreurs.

1. Traiter les Functions comme un portage Script 1:1. Ce n’est pas le cas. Une seule Function peut remplacer trois Scripts avec un branchement plus propre. Auditez vos Scripts comme un système avant de les réécrire.

2. Oublier les scopes de lecture. De nombreuses Functions ont besoin de read_customers, read_orders ou write_discounts. Ajoutez-les dans shopify.app.toml sous scopes et réautorisez l’app, sinon votre requête d’entrée renverra null.

3. Exécuter les Functions sur des clients non balisés sans test de parité. Même si votre code semble correct, les cas limites (panier vide, cartes-cadeaux, crédit boutique, brouillons B2B) révéleront des problèmes. Un déploiement progressif par tag vous coûte deux jours et vous évite une panne P1.

4. Sauter le Customizations Report. C’est le meilleur inventaire de ce qui tourne réellement. Ne migrez pas depuis la mémoire — migrez depuis le rapport.

5. Codifier en dur les IDs de collections et les tags clients. Utilisez la configuration de Function via des metafields si vous avez besoin de valeurs ajustables par le marchand. La CLI peut scaffold une configuration basée sur des metafields — voir la documentation Shopify sur la configuration des Functions.

Checklist de migration pour les 75 prochains jours

Un plan réaliste semaine par semaine pour arriver sereinement au 30 juin.

Semaine

Action

Semaine 1 (cette semaine)

Récupérez le Customizations Report. Inventoriez chaque Script. Décidez : Function, app publique ou suppression.

Semaines 2–3

Configurez l’environnement de développement local. Scaffold la première Function. Migrez le Script le plus simple (généralement une règle de masquage de paiement).

Semaines 4–6

Migrez les Scripts de remise. Ce sont eux qui prennent le plus de temps, car l’API Discounts est la plus riche. Testez minutieusement avec des tags.

Semaines 7–8

Migrez les Scripts d’expédition / livraison. Activez les Delivery Customizations via l’Admin.

Semaines 9–10

Mettez en place le pipeline CI. Déplacez tous les déploiements hors des ordinateurs portables des développeurs.

Semaine 11 (mi-juin)

Vérification finale de parité. Dépubliez tous les Scripts. Faites tourner la boutique uniquement sur les Functions pendant deux semaines.

30 juin

Le jour de la bascule arrive. Rien ne casse parce que vous avez terminé tôt.

Si vous commencez cette semaine, vous avez de la marge. Si vous commencez en juin, vous n’en avez pas.


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

Questions fréquemment posées

Ai-je besoin de Shopify Plus pour utiliser les Functions ?

Les Functions personnalisées nécessitent Shopify Plus, mais les Functions d’apps publiques fonctionnent sur tous les plans. Si vous n’êtes pas sur Plus, vous avez deux options : installer depuis le Shopify App Store une app publique qui fournit la Function pour vous, ou passer à Plus pour écrire vos propres Functions personnalisées. La plupart des grands marchands qui avaient des Scripts étaient déjà sur Plus, donc cela ne change que rarement quoi que ce soit en pratique.

Puis-je écrire des Functions en TypeScript ?

Oui — TypeScript est entièrement pris en charge et la CLI le scaffold pour vous. Quand vous exécutez shopify app generate extension et choisissez « JavaScript », le projet généré inclut des déclarations de types depuis import("../generated/api"). Vous pouvez convertir les fichiers en .ts et ajouter un tsconfig.json si vous préférez. Le résultat compilé (WASM) est identique quel que soit le langage source.

À quelle vitesse s’exécutent les Functions par rapport aux Scripts ?

Les Functions s’exécutent généralement en moins de 5 ms — nettement plus vite que les Scripts Ruby. Comme elles sont compilées en WebAssembly et tournent dans un runtime très serré, Shopify impose une limite d’exécution de 5 ms. Si votre Function la dépasse, l’opération est ignorée et votre Function ne renvoie aucune opération. En pratique, une Function bien écrite utilise 1 à 2 ms. Le plafond de performance est bien plus élevé que celui des Scripts.

Une Function peut-elle appeler une API externe ?

Non — les Functions ne peuvent pas effectuer de requêtes réseau. Elles font uniquement du calcul pur : données d’entrée du panier → opérations de sortie. Si vous avez besoin de données externes (une recherche CRM, une vérification d’inventaire en temps réel), vous devrez soit stocker ces données à l’avance dans des metafields, soit utiliser une autre surface (App Proxy, webhooks, Cart Transform avec recherche côté backend). C’est la raison la plus courante pour laquelle les équipes doivent repenser la solution plutôt que simplement porter le code.

Quelle est la différence entre Cart Transform et Discounts ?

Les Discounts appliquent des changements de prix ; Cart Transform modifie le contenu du panier. Utilisez l’API Discounts pour appliquer -10 %, la livraison gratuite ou un BOGO. Utilisez Cart Transform pour regrouper deux produits en une seule ligne, ou découper un variant en plusieurs. Beaucoup d’anciens Scripts mélangeaient les deux sujets — lors de la migration, séparez-les en deux Functions.

Comment tester une Function localement sans boutique de développement ?

Vous pouvez exécuter des tests unitaires avec cargo test (Rust) ou npm test (JS), mais le test d’intégration complet nécessite une boutique de développement. La CLI fournit shopify app function run, qui exécute votre Function sur un fichier d’entrée exemple — utile pour itérer rapidement. Mais pour confirmer le comportement du checkout de bout en bout, il vous faut une vraie boutique avec un vrai panier.

Puis-je avoir plusieurs Functions du même type ?

Oui — Shopify prend en charge plusieurs Functions par cible, et elles s’exécutent dans un ordre déterministe. Pour les remises, l’ordre est régi par les règles de cumul de remises de Shopify. Pour les Delivery et Payment Customizations, vous pouvez chaîner des Functions, mais chaque sortie alimente la suivante. La plupart des équipes utilisent une Function par type pour simplifier.

Que devient mon Script après le déploiement de la Function ?

Les deux s’exécutent en parallèle jusqu’à ce que vous dépubliiez le Script dans Apps → Script Editor. C’est intentionnel — cela vous donne la fenêtre de test en parallèle. Après avoir vérifié que la Function fonctionne, dépubliez manuellement le Script. Après le 30 juin 2026, tous les Scripts cessent de s’exécuter, que vous les ayez dépubliés ou non.

La migration affectera-t-elle mon SEO ou mon thème ?

Non — les Functions s’exécutent côté serveur au checkout et ne touchent jamais votre thème ni vos pages produit. Elles ne modifient que les remises, les options d’expédition et les moyens de paiement au checkout. Votre vitrine, vos templates produit et votre SEO restent totalement intacts.

Comment migrer un Script qui utilise Input.line_items avec des propriétés personnalisées ?

Les propriétés personnalisées sont accessibles via le champ attribute sur les lignes de panier dans l’entrée GraphQL. Ajoutez attribute(key: "your-key") { value } à l’intérieur de la sélection lines. La Function les lit de la même manière que les Scripts lisaient les propriétés de line item — simplement via GraphQL au lieu d’appels de méthodes Ruby.

Qu’en est-il des analytics et des tags de commande ? Les Functions peuvent-elles écrire des données ?

Les Functions ne peuvent pas écrire de tags de commande ni déclencher elles-mêmes des webhooks — elles ne renvoient que des opérations sur le panier actuel. Pour le tagging ou les workflows en aval, utilisez Shopify Flow déclenché par l’événement de création de commande. De nombreux marchands combinent une Function (pour la remise) avec un Flow (pour tagger la commande avec « VOLUME-DISCOUNT-APPLIED »).

Existe-t-il une app publique que je peux installer au lieu de construire une Function personnalisée ?

Oui — le Shopify App Store propose des dizaines d’apps qui encapsulent des Functions pour les cas d’usage courants. Cherchez « discount function », « delivery customization » ou « payment customization ». Pour des cas simples (remises sur volume, masquage de moyens de paiement par tag, livraison gratuite au-dessus de X), une app existante peut vous faire gagner des jours de travail. Réservez les Functions personnalisées à une logique réellement unique à votre activité.

Que se passe-t-il si je rate la date limite du 30 juin ?

Le Script cesse de s’exécuter — il n’y a ni repli, ni délai de grâce, ni prolongation. Ce que faisait le Script (la remise, le tarif de livraison masqué, le moyen de paiement bloqué) revient au comportement par défaut à minuit UTC le 1er juillet. Si votre activité dépend de cette logique, prévoyez d’être en ligne bien avant cette date. La migration prend plus de temps que la plupart des équipes ne l’estiment, surtout avec les tests de parité.

Puis-je supprimer complètement l’application Script Editor ?

Vous pouvez la désinstaller après le 30 juin 2026, mais Shopify la supprimera probablement automatiquement. Une fois les Scripts arrêtés, l’éditeur n’a plus d’utilité. Vous pouvez aussi dépublier tous les Scripts maintenant et désinstaller l’app immédiatement si vous avez terminé la migration — vos Functions sont indépendantes.

Que faire cette semaine

Ne lisez pas cet article pour fermer ensuite l’onglet. Faites ces quatre choses dans les sept prochains jours.

1. Récupérez le Customizations Report. Allez dans Settings → Checkout → Customizations Report. Exportez-le. C’est votre backlog de migration.

2. Configurez votre environnement de développement. Installez Node 18+, Shopify CLI et Rust (le cas échéant). Vérifiez que shopify version fonctionne. Temps total : 30 minutes.

3. Scaffold et expédiez une toute petite Function sur une boutique de développement. Prenez le Script le plus simple que vous avez — généralement une règle de masquage de paiement. Migrez-le de bout en bout. Même s’il n’arrive jamais en production, vous aurez validé la chaîne d’outils.

4. Réservez du temps dans le calendrier pour les huit prochaines semaines. Les migrations ne se font pas dans les moments libres entre deux sprints. Bloquez un créneau récurrent — par exemple tous les mardis et jeudis après-midi — et traitez-le comme une release.

D’après les équipes que nous avons vues migrer, le schéma est toujours le même : deux semaines d’hésitation, trois semaines de vrai travail, une semaine de nettoyage. Cela fait six semaines. Vous en avez dix. La marge existe — utilisez-la pour les revues de code et l’assurance qualité, pas pour repousser le démarrage.

Et une fois votre logique de checkout réglée, la prochaine chose que la plupart des équipes traitent est l’après-achat — changements d’adresse client, échanges, ajouts de remises après la commande. Si cela fait partie de votre feuille de route (et cela devrait l’être, que vous soyez un opérateur Plus à gros volume ou une boutique Advanced centrée sur l’expérience client), Revize est sur le Shopify App Store et fonctionne aux côtés de chaque Function que vous construirez ici.

Ressources

Articles associés

Nous sommes le 16 avril 2026. Hier — le 15 avril — était le jour où Shopify a verrouillé définitivement l’éditeur de Scripts. Vous ne pouvez plus créer ni publier de nouveau Script. L’arrêt d’exécution arrivera dans 75 jours, le 30 juin 2026.

Si vous êtes développeur Shopify Plus — ou l’agence qui gère une boutique Plus — et que vous avez repoussé cette migration à « la prochaine sprint » pendant les douze derniers mois, vous avez un problème. Pas un problème du type « ce serait bien à corriger ». Un problème du type « votre checkout casse à minuit le 1er juillet ». La plupart des boutiques Plus ont accumulé 5 à 20 Scripts au fil des ans, chacun alimentant discrètement une règle de remise, un masquage d’expédition ou une restriction de paiement dont plus personne ne se souvient avoir écrit le code.

Ce guide est le manuel technique de migration que nous aurions voulu avoir en janvier. Il couvre le vrai code — pas seulement la stratégie. Une fois votre lecture terminée, vous saurez comment scaffold une Function avec Shopify CLI, écrire la logique Rust ou JavaScript pour les remises, les personnalisations de livraison et les personnalisations de paiement, la tester prudemment sur un sous-ensemble balisé de vos clients, puis la déployer en production sans casser votre checkout existant.

Retirons les Scripts de votre boutique et mettons-y les Functions.


Developer migrating Shopify Scripts to Shopify Functions modules

Réponse rapide : Scripts → Functions en 60 secondes

La migration en un paragraphe : les Shopify Scripts (code Ruby dans l’éditeur de Scripts, réservé à Plus) sont remplacés par les Shopify Functions (modules WebAssembly écrits en Rust ou en JavaScript, disponibles sur tous les plans). Vous créez une Function avec shopify app generate extension, vous écrivez une requête run.graphql qui récupère les données de panier dont vous avez besoin, vous écrivez un fichier run.rs ou run.js qui renvoie des opérations (remises, méthodes d’expédition masquées, etc.), puis vous déployez avec shopify app deploy et l’activez via l’Admin ou une mutation GraphQL. Les Functions s’exécutent en WASM compilé avec une latence inférieure à 5 ms, fonctionnent sur tous les plans et constituent désormais le seul chemin de personnalisation pris en charge par Shopify.

Ce qui change réellement le 30 juin

Avant de toucher au code, mettons les dates au clair. Il y en a deux, et elles comptent toutes les deux.

Date

Ce qui se passe

Votre action

15 avril 2026 (passé)

L’éditeur de Scripts est en lecture seule. Plus de nouveaux Scripts. Plus de modifications des Scripts existants.

Les Scripts existants s’exécutent encore. Migrez maintenant ou figez votre logique.

30 juin 2026

Tous les Shopify Scripts cessent de s’exécuter. Point final.

Votre remplacement par une Function doit être en ligne avant cette date.

La migration est binaire. Soit votre Function est déployée d’ici le 30 juin et votre checkout continue de fonctionner, soit ce n’est pas le cas — et chaque panier concerné retombe silencieusement sur la tarification standard, les frais de livraison standard et tous les moyens de paiement activés. Il n’y a pas de demi-mesure. Le Script s’exécute ou non, et après le 30 juin, il ne s’exécute plus.

Astuce : Ouvrez Settings → Checkout → Customizations Report dans votre administration Shopify. Cela liste chaque Script actif de votre boutique, ce qu’il fait et le type de remplacement par Function recommandé. Commencez par là.

Functions vs Scripts : ce qui a vraiment changé

Dimension

Shopify Scripts (obsolètes)

Shopify Functions (remplacement)

Langage

DSL Ruby (spécifique à Shopify)

Rust, JavaScript, TypeScript

Runtime

Ruby sandboxé sur l’infrastructure Shopify

WebAssembly (WASM) — exécution sous les 5 ms

Disponibilité selon le plan

Uniquement Plus

Tous les plans (les apps personnalisées nécessitent Plus ; les apps publiques sont ouvertes)

Éditeur

Éditeur de Scripts dans l’admin

IDE local + Shopify CLI

Versioning

Aucun — modifications en direct

Compatible Git — contrôle de version complet

Tests

Manuel dans le checkout

Développement local avec shopify app dev, liens de prévisualisation

Déploiement

Cliquer sur « Enregistrer » dans l’admin

shopify app deploy depuis le terminal

Cibles

Articles, expédition, paiements

Remises, transformation du panier, validation, personnalisation de livraison, personnalisation de paiement, routage des commandes, contraintes de fulfillment, et plus

Le changement architectural est important. Les Scripts, c’était « retoucher du Ruby dans une zone de texte ». Les Functions, c’est « écrire une vraie application, la versionner, la tester localement, la déployer via un vrai pipeline CI ». La courbe d’apprentissage est plus raide. Mais c’est aussi la dernière migration que vous ferez pour la logique de checkout dans un avenir prévisible — les Functions sont l’engagement à long terme de Shopify, pas un palliatif comme l’étaient finalement les Scripts.

Associer vos Scripts au bon type de Function

Chaque Script que vous avez aujourd’hui correspond à une seule API Function. Voici le tableau de correspondance à garder sous les yeux.

Ancien type de Script

Ce qu’il faisait

Nouvelle API Function

Cible de la Function

Line Item Script

Appliquer des remises à des produits / clients / conditions de panier spécifiques

Cart & Checkout Discounts API

cart.lines.discounts.generate.run

Shipping Script (remise)

Livraison gratuite / remisée selon les règles du panier

Cart & Checkout Discounts API

cart.delivery-options.discounts.generate.run

Shipping Script (masquer / renommer / réordonner)

Masquer un tarif de livraison au-dessus de X $, renommer « Standard » en « Gratuit au-delà de 50 $ »

Delivery Customization API

cart.delivery-options.transform.run

Payment Script

Masquer PayPal pour le B2B, masquer le paiement à la livraison au-dessus de 500 $, réordonner les moyens

Payment Customization API

cart.payment-methods.transform.run

Script de modification du panier (rare)

Regrouper des produits, remplacer des line items

Cart Transform API

cart.transform.run

Script de blocage du checkout

Refuser le panier si le mélange de SKU est invalide

Cart & Checkout Validation API

cart.validations.generate.run

Si vous avez dix Scripts, vous construirez probablement trois à cinq Functions — plusieurs Scripts se regroupent souvent en une seule Function avec une logique de branchement plus propre.


Shopify Functions unifying discounts, delivery, and payment customizations

Prérequis : configurer votre environnement de développement local

Avant de scaffold une Function, vous devez installer trois éléments en local. Lancez ces vérifications dans votre terminal.

1. Node.js 18+

node --version
# Doit être >= 18.0.0

Si votre version est plus ancienne, installez-la via nvm ou téléchargez-la depuis nodejs.org.

2. Shopify CLI 3+

npm install -g @shopify/cli@latest
shopify version
# Devrait afficher 3.x ou plus

3. Chaîne d’outils Rust (uniquement si vous écrivez vos Functions en Rust)

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

Les Functions JavaScript n’ont pas besoin de Rust. Choisissez un langage pour votre équipe et tenez-vous-y — en utiliser deux ajoute une surcharge de maintenance.

4. Une boutique de développement

Connectez-vous à votre tableau de bord Partner et créez une nouvelle boutique de développement, ou utilisez-en une existante. Vous déploierez les Functions sur cette boutique avant de passer en production.

Scaffolder votre première Function

La CLI génère la majeure partie du boilerplate. Dans n’importe quel répertoire :

# Créez une nouvelle app Shopify (ignorez cette étape si vous en avez déjà une)
shopify app init my-checkout-functions
cd my-checkout-functions

# Générez une extension Function
shopify app generate extension

La CLI vous guide à travers les invites. Pour une Function de remise, vous choisiriez :

  • Type : Function

  • Template : discount (ou cart_checkout_validation, delivery_customization, payment_customization, etc.)

  • Langage : Rust ou JavaScript

  • Nom : quelque chose comme volume-discount-fn

Cela crée extensions/volume-discount-fn/ avec :

extensions/volume-discount-fn/
├── shopify.extension.toml      # Configuration de la Function cibles, build, version
├── src/
├── cart_lines_discounts_generate_run.graphql   # Requête d’entrée
└── cart_lines_discounts_generate_run.rs        # Logique de la Function
├── Cargo.toml                  # Dépendances Rust (Rust uniquement)
└── README.md

Les trois fichiers que vous modifierez constamment sont le .toml (configuration), le .graphql (entrée) et le .rs / .js (logique). C’est tout.

Tutoriel 1 : remplacer un Line Item Script (remise sur volume)

Supposons que votre ancien Script accordait 10 % de remise sur le sous-total de la commande lorsque le panier contenait 5 unités ou plus d’une collection spécifique. Voici l’équivalent en Function.

Étape 1.1 : la configuration (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"]

Étape 1.2 : la requête d’entrée (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
  }
}

Astuce : Les Functions ne voient que les données que vous interrogez. Gardez le GraphQL minimal — chaque champ que vous omettez signifie une exécution plus rapide et moins coûteuse.

Étape 1.3 : la logique (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> {
    // Quitter si la classe de remise ne correspond pas
    let has_order_discount = input
        .discount()
        .discount_classes()
        .contains(&schema::DiscountClass::Order);

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

    // Additionner les quantités des articles de la collection cible
    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![] });
    }

    // Appliquer 10 % de remise sur le sous-total de la commande
    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,
                }],
            },
        )],
    })
}

Étape 1.4 : tester, déployer, activer

# Développement local avec rechargement à chaud
shopify app dev

# Une fois prêt, déployez
shopify app deploy

# Dans le panneau GraphiQL qui s’ouvre (appuyez sur `g` dans le terminal de dev),
# créez la remise automatique qui utilise votre 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 }
  }
}

C’est tout. La Function est en ligne, versionnée, et remplace entièrement l’ancien Script.

Tutoriel 2 : remplacer un Shipping Script (masquer une méthode au-dessus d’un seuil de panier)

Script courant : « Masquer la livraison Express lorsque le sous-total du panier dépasse 500 $ afin d’éviter une expédition de nuit coûteuse sur les grosses commandes. » Voici la version Function en Delivery Customization.

Étape 2.1 : scaffold

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

Étape 2.2 : requête d’entrée (src/run.graphql)

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

Étape 2.3 : logique (src/run.js — variante JavaScript)

// @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 };
}

Étape 2.4 : activation via l’Admin (aucun GraphQL requis)

Les Delivery Customizations disposent aussi d’une interface d’administration intégrée. Après shopify app deploy :

  1. Allez dans Settings → Shipping and delivery

  2. Faites défiler jusqu’à la section Customizations en bas

  3. Cliquez sur Add customization → sélectionnez votre Function

  4. Enregistrez

La règle de masquage est active en production. Aucune mutation n’est nécessaire.


Shopify delivery customization Function hiding shipping option at checkout

Tutoriel 3 : remplacer un Payment Script (masquer le paiement à la livraison pour le B2B)

Ancien Script : « Masquer le paiement à la livraison pour tout client ayant le tag 'B2B'. » Voici la version Payment Customization.

Étape 3.1 : scaffold

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

Étape 3.2 : requête d’entrée

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

Étape 3.3 : logique (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 } }],
  };
}

Étape 3.4 : activation

Les Payment Customizations disposent aussi d’une interface d’administration sous Settings → Payments → Customizations. Même processus que pour la livraison — choisissez votre Function, enregistrez, terminé.

Puisque vous lisez ceci — un mot sur l’après-achat

Petite précision puisque c’est le blog de Revize. Revize gère ce que les Functions ne peuvent pas toucher — une fois qu’une commande est passée, les clients veulent ajouter un article, changer une taille, corriger l’adresse de livraison, appliquer une remise qu’ils ont oubliée. Les Functions vivent au checkout. Revize vit après le checkout. Les Functions décident de ce qui est autorisé dans le panier ; Revize permet à vos clients et à votre équipe support de modifier la commande ensuite sans passer par un cycle remboursement + recréation. Cela compte pour deux types de boutiques : celles qui ont suffisamment de volume de commandes pour que l’édition manuelle s’effondre (les opérateurs Plus, évidemment, mais aussi les boutiques Advanced à fort débit), et celles dont toute la marque repose sur l’expérience client — où un e-mail du type « désolé, nous ne pouvons pas modifier cela » tue les achats répétés.

Si votre plan de migration couvre Scripts → Functions mais que vous n’avez jamais réglé les modifications de commandes après achat, vous allez heurter le prochain mur « pourquoi est-ce si compliqué ? » dans environ trois semaines. Le guide de gestion des commandes que nous venons de publier décrit tout le plan de bataille post-checkout.

Retour à la migration.

Stratégie de test : le modèle du client balisé

Les Functions n’ont pas de « mode brouillon » que vous pouvez activer ou désactiver dans l’admin. La méthode professionnelle consiste à conditionner la nouvelle Function à un tag client, à faire fonctionner en parallèle l’ancien Script et la nouvelle Function, à vérifier qu’ils produisent une sortie identique pour les utilisateurs balisés, puis à basculer.

Étape 1 : taguez vos utilisateurs de test

Dans Customers, ajoutez le tag FN-TESTER à deux ou trois comptes internes.

Étape 2 : branchez la Function sur la présence du tag

// En haut de votre fonction run
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);  // Laisser passer vers le Script existant
}

// La nouvelle logique de la Function ne s’exécute que pour les utilisateurs balisés

Étape 3 : ajoutez hasAnyTag à votre requête d’entrée

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

Étape 4 : vérifiez dans le checkout

Connectez-vous en tant qu’utilisateur balisé, parcourez le checkout, confirmez que la Function se déclenche. Connectez-vous en tant qu’utilisateur non balisé, confirmez que l’ancien Script s’exécute toujours. Quand la parité tient pendant quelques jours, retirez la vérification du tag et laissez la Function s’exécuter pour tout le monde.

Étape 5 : dépubliez l’ancien Script

Allez dans Apps → Script Editor → [Your Script] → Unpublish. Une fois dépublié, la Function devient la seule source de vérité.

Un workflow de déploiement qui passe vraiment à l’échelle

Ne déployez pas éternellement depuis l’ordinateur portable d’un développeur. Une fois un ou deux Scripts migrés, mettez en place un vrai pipeline CI.

Le workflow minimal viable

# .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 }}

Générez le jeton Partner depuis votre tableau de bord Partner sous Settings → Tokens. Désormais, chaque fusion dans main déploie vos Functions. Fini les fils Slack du genre « Mike a-t-il déployé ça ? ».

Versioning et rollback

shopify app deploy crée un instantané versionné. Pour revenir en arrière :

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

Comparé aux Scripts — où le rollback voulait dire « se souvenir de l’ancien code et le recoller » — c’est le jour et la nuit.


Shopify Functions deployment pipeline across local staging and production environments

Ce que la plupart des équipes font mal

Après avoir accompagné des marchands Plus dans cette migration au cours de l’année écoulée, on retrouve toujours les cinq mêmes erreurs.

1. Traiter les Functions comme un portage Script 1:1. Ce n’est pas le cas. Une seule Function peut remplacer trois Scripts avec un branchement plus propre. Auditez vos Scripts comme un système avant de les réécrire.

2. Oublier les scopes de lecture. De nombreuses Functions ont besoin de read_customers, read_orders ou write_discounts. Ajoutez-les dans shopify.app.toml sous scopes et réautorisez l’app, sinon votre requête d’entrée renverra null.

3. Exécuter les Functions sur des clients non balisés sans test de parité. Même si votre code semble correct, les cas limites (panier vide, cartes-cadeaux, crédit boutique, brouillons B2B) révéleront des problèmes. Un déploiement progressif par tag vous coûte deux jours et vous évite une panne P1.

4. Sauter le Customizations Report. C’est le meilleur inventaire de ce qui tourne réellement. Ne migrez pas depuis la mémoire — migrez depuis le rapport.

5. Codifier en dur les IDs de collections et les tags clients. Utilisez la configuration de Function via des metafields si vous avez besoin de valeurs ajustables par le marchand. La CLI peut scaffold une configuration basée sur des metafields — voir la documentation Shopify sur la configuration des Functions.

Checklist de migration pour les 75 prochains jours

Un plan réaliste semaine par semaine pour arriver sereinement au 30 juin.

Semaine

Action

Semaine 1 (cette semaine)

Récupérez le Customizations Report. Inventoriez chaque Script. Décidez : Function, app publique ou suppression.

Semaines 2–3

Configurez l’environnement de développement local. Scaffold la première Function. Migrez le Script le plus simple (généralement une règle de masquage de paiement).

Semaines 4–6

Migrez les Scripts de remise. Ce sont eux qui prennent le plus de temps, car l’API Discounts est la plus riche. Testez minutieusement avec des tags.

Semaines 7–8

Migrez les Scripts d’expédition / livraison. Activez les Delivery Customizations via l’Admin.

Semaines 9–10

Mettez en place le pipeline CI. Déplacez tous les déploiements hors des ordinateurs portables des développeurs.

Semaine 11 (mi-juin)

Vérification finale de parité. Dépubliez tous les Scripts. Faites tourner la boutique uniquement sur les Functions pendant deux semaines.

30 juin

Le jour de la bascule arrive. Rien ne casse parce que vous avez terminé tôt.

Si vous commencez cette semaine, vous avez de la marge. Si vous commencez en juin, vous n’en avez pas.


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

Questions fréquemment posées

Ai-je besoin de Shopify Plus pour utiliser les Functions ?

Les Functions personnalisées nécessitent Shopify Plus, mais les Functions d’apps publiques fonctionnent sur tous les plans. Si vous n’êtes pas sur Plus, vous avez deux options : installer depuis le Shopify App Store une app publique qui fournit la Function pour vous, ou passer à Plus pour écrire vos propres Functions personnalisées. La plupart des grands marchands qui avaient des Scripts étaient déjà sur Plus, donc cela ne change que rarement quoi que ce soit en pratique.

Puis-je écrire des Functions en TypeScript ?

Oui — TypeScript est entièrement pris en charge et la CLI le scaffold pour vous. Quand vous exécutez shopify app generate extension et choisissez « JavaScript », le projet généré inclut des déclarations de types depuis import("../generated/api"). Vous pouvez convertir les fichiers en .ts et ajouter un tsconfig.json si vous préférez. Le résultat compilé (WASM) est identique quel que soit le langage source.

À quelle vitesse s’exécutent les Functions par rapport aux Scripts ?

Les Functions s’exécutent généralement en moins de 5 ms — nettement plus vite que les Scripts Ruby. Comme elles sont compilées en WebAssembly et tournent dans un runtime très serré, Shopify impose une limite d’exécution de 5 ms. Si votre Function la dépasse, l’opération est ignorée et votre Function ne renvoie aucune opération. En pratique, une Function bien écrite utilise 1 à 2 ms. Le plafond de performance est bien plus élevé que celui des Scripts.

Une Function peut-elle appeler une API externe ?

Non — les Functions ne peuvent pas effectuer de requêtes réseau. Elles font uniquement du calcul pur : données d’entrée du panier → opérations de sortie. Si vous avez besoin de données externes (une recherche CRM, une vérification d’inventaire en temps réel), vous devrez soit stocker ces données à l’avance dans des metafields, soit utiliser une autre surface (App Proxy, webhooks, Cart Transform avec recherche côté backend). C’est la raison la plus courante pour laquelle les équipes doivent repenser la solution plutôt que simplement porter le code.

Quelle est la différence entre Cart Transform et Discounts ?

Les Discounts appliquent des changements de prix ; Cart Transform modifie le contenu du panier. Utilisez l’API Discounts pour appliquer -10 %, la livraison gratuite ou un BOGO. Utilisez Cart Transform pour regrouper deux produits en une seule ligne, ou découper un variant en plusieurs. Beaucoup d’anciens Scripts mélangeaient les deux sujets — lors de la migration, séparez-les en deux Functions.

Comment tester une Function localement sans boutique de développement ?

Vous pouvez exécuter des tests unitaires avec cargo test (Rust) ou npm test (JS), mais le test d’intégration complet nécessite une boutique de développement. La CLI fournit shopify app function run, qui exécute votre Function sur un fichier d’entrée exemple — utile pour itérer rapidement. Mais pour confirmer le comportement du checkout de bout en bout, il vous faut une vraie boutique avec un vrai panier.

Puis-je avoir plusieurs Functions du même type ?

Oui — Shopify prend en charge plusieurs Functions par cible, et elles s’exécutent dans un ordre déterministe. Pour les remises, l’ordre est régi par les règles de cumul de remises de Shopify. Pour les Delivery et Payment Customizations, vous pouvez chaîner des Functions, mais chaque sortie alimente la suivante. La plupart des équipes utilisent une Function par type pour simplifier.

Que devient mon Script après le déploiement de la Function ?

Les deux s’exécutent en parallèle jusqu’à ce que vous dépubliiez le Script dans Apps → Script Editor. C’est intentionnel — cela vous donne la fenêtre de test en parallèle. Après avoir vérifié que la Function fonctionne, dépubliez manuellement le Script. Après le 30 juin 2026, tous les Scripts cessent de s’exécuter, que vous les ayez dépubliés ou non.

La migration affectera-t-elle mon SEO ou mon thème ?

Non — les Functions s’exécutent côté serveur au checkout et ne touchent jamais votre thème ni vos pages produit. Elles ne modifient que les remises, les options d’expédition et les moyens de paiement au checkout. Votre vitrine, vos templates produit et votre SEO restent totalement intacts.

Comment migrer un Script qui utilise Input.line_items avec des propriétés personnalisées ?

Les propriétés personnalisées sont accessibles via le champ attribute sur les lignes de panier dans l’entrée GraphQL. Ajoutez attribute(key: "your-key") { value } à l’intérieur de la sélection lines. La Function les lit de la même manière que les Scripts lisaient les propriétés de line item — simplement via GraphQL au lieu d’appels de méthodes Ruby.

Qu’en est-il des analytics et des tags de commande ? Les Functions peuvent-elles écrire des données ?

Les Functions ne peuvent pas écrire de tags de commande ni déclencher elles-mêmes des webhooks — elles ne renvoient que des opérations sur le panier actuel. Pour le tagging ou les workflows en aval, utilisez Shopify Flow déclenché par l’événement de création de commande. De nombreux marchands combinent une Function (pour la remise) avec un Flow (pour tagger la commande avec « VOLUME-DISCOUNT-APPLIED »).

Existe-t-il une app publique que je peux installer au lieu de construire une Function personnalisée ?

Oui — le Shopify App Store propose des dizaines d’apps qui encapsulent des Functions pour les cas d’usage courants. Cherchez « discount function », « delivery customization » ou « payment customization ». Pour des cas simples (remises sur volume, masquage de moyens de paiement par tag, livraison gratuite au-dessus de X), une app existante peut vous faire gagner des jours de travail. Réservez les Functions personnalisées à une logique réellement unique à votre activité.

Que se passe-t-il si je rate la date limite du 30 juin ?

Le Script cesse de s’exécuter — il n’y a ni repli, ni délai de grâce, ni prolongation. Ce que faisait le Script (la remise, le tarif de livraison masqué, le moyen de paiement bloqué) revient au comportement par défaut à minuit UTC le 1er juillet. Si votre activité dépend de cette logique, prévoyez d’être en ligne bien avant cette date. La migration prend plus de temps que la plupart des équipes ne l’estiment, surtout avec les tests de parité.

Puis-je supprimer complètement l’application Script Editor ?

Vous pouvez la désinstaller après le 30 juin 2026, mais Shopify la supprimera probablement automatiquement. Une fois les Scripts arrêtés, l’éditeur n’a plus d’utilité. Vous pouvez aussi dépublier tous les Scripts maintenant et désinstaller l’app immédiatement si vous avez terminé la migration — vos Functions sont indépendantes.

Que faire cette semaine

Ne lisez pas cet article pour fermer ensuite l’onglet. Faites ces quatre choses dans les sept prochains jours.

1. Récupérez le Customizations Report. Allez dans Settings → Checkout → Customizations Report. Exportez-le. C’est votre backlog de migration.

2. Configurez votre environnement de développement. Installez Node 18+, Shopify CLI et Rust (le cas échéant). Vérifiez que shopify version fonctionne. Temps total : 30 minutes.

3. Scaffold et expédiez une toute petite Function sur une boutique de développement. Prenez le Script le plus simple que vous avez — généralement une règle de masquage de paiement. Migrez-le de bout en bout. Même s’il n’arrive jamais en production, vous aurez validé la chaîne d’outils.

4. Réservez du temps dans le calendrier pour les huit prochaines semaines. Les migrations ne se font pas dans les moments libres entre deux sprints. Bloquez un créneau récurrent — par exemple tous les mardis et jeudis après-midi — et traitez-le comme une release.

D’après les équipes que nous avons vues migrer, le schéma est toujours le même : deux semaines d’hésitation, trois semaines de vrai travail, une semaine de nettoyage. Cela fait six semaines. Vous en avez dix. La marge existe — utilisez-la pour les revues de code et l’assurance qualité, pas pour repousser le démarrage.

Et une fois votre logique de checkout réglée, la prochaine chose que la plupart des équipes traitent est l’après-achat — changements d’adresse client, échanges, ajouts de remises après la commande. Si cela fait partie de votre feuille de route (et cela devrait l’être, que vous soyez un opérateur Plus à gros volume ou une boutique Advanced centrée sur l’expérience client), Revize est sur le Shopify App Store et fonctionne aux côtés de chaque Function que vous construirez ici.

Ressources

Articles associés

Nous sommes le 16 avril 2026. Hier — le 15 avril — était le jour où Shopify a verrouillé définitivement l’éditeur de Scripts. Vous ne pouvez plus créer ni publier de nouveau Script. L’arrêt d’exécution arrivera dans 75 jours, le 30 juin 2026.

Si vous êtes développeur Shopify Plus — ou l’agence qui gère une boutique Plus — et que vous avez repoussé cette migration à « la prochaine sprint » pendant les douze derniers mois, vous avez un problème. Pas un problème du type « ce serait bien à corriger ». Un problème du type « votre checkout casse à minuit le 1er juillet ». La plupart des boutiques Plus ont accumulé 5 à 20 Scripts au fil des ans, chacun alimentant discrètement une règle de remise, un masquage d’expédition ou une restriction de paiement dont plus personne ne se souvient avoir écrit le code.

Ce guide est le manuel technique de migration que nous aurions voulu avoir en janvier. Il couvre le vrai code — pas seulement la stratégie. Une fois votre lecture terminée, vous saurez comment scaffold une Function avec Shopify CLI, écrire la logique Rust ou JavaScript pour les remises, les personnalisations de livraison et les personnalisations de paiement, la tester prudemment sur un sous-ensemble balisé de vos clients, puis la déployer en production sans casser votre checkout existant.

Retirons les Scripts de votre boutique et mettons-y les Functions.


Developer migrating Shopify Scripts to Shopify Functions modules

Réponse rapide : Scripts → Functions en 60 secondes

La migration en un paragraphe : les Shopify Scripts (code Ruby dans l’éditeur de Scripts, réservé à Plus) sont remplacés par les Shopify Functions (modules WebAssembly écrits en Rust ou en JavaScript, disponibles sur tous les plans). Vous créez une Function avec shopify app generate extension, vous écrivez une requête run.graphql qui récupère les données de panier dont vous avez besoin, vous écrivez un fichier run.rs ou run.js qui renvoie des opérations (remises, méthodes d’expédition masquées, etc.), puis vous déployez avec shopify app deploy et l’activez via l’Admin ou une mutation GraphQL. Les Functions s’exécutent en WASM compilé avec une latence inférieure à 5 ms, fonctionnent sur tous les plans et constituent désormais le seul chemin de personnalisation pris en charge par Shopify.

Ce qui change réellement le 30 juin

Avant de toucher au code, mettons les dates au clair. Il y en a deux, et elles comptent toutes les deux.

Date

Ce qui se passe

Votre action

15 avril 2026 (passé)

L’éditeur de Scripts est en lecture seule. Plus de nouveaux Scripts. Plus de modifications des Scripts existants.

Les Scripts existants s’exécutent encore. Migrez maintenant ou figez votre logique.

30 juin 2026

Tous les Shopify Scripts cessent de s’exécuter. Point final.

Votre remplacement par une Function doit être en ligne avant cette date.

La migration est binaire. Soit votre Function est déployée d’ici le 30 juin et votre checkout continue de fonctionner, soit ce n’est pas le cas — et chaque panier concerné retombe silencieusement sur la tarification standard, les frais de livraison standard et tous les moyens de paiement activés. Il n’y a pas de demi-mesure. Le Script s’exécute ou non, et après le 30 juin, il ne s’exécute plus.

Astuce : Ouvrez Settings → Checkout → Customizations Report dans votre administration Shopify. Cela liste chaque Script actif de votre boutique, ce qu’il fait et le type de remplacement par Function recommandé. Commencez par là.

Functions vs Scripts : ce qui a vraiment changé

Dimension

Shopify Scripts (obsolètes)

Shopify Functions (remplacement)

Langage

DSL Ruby (spécifique à Shopify)

Rust, JavaScript, TypeScript

Runtime

Ruby sandboxé sur l’infrastructure Shopify

WebAssembly (WASM) — exécution sous les 5 ms

Disponibilité selon le plan

Uniquement Plus

Tous les plans (les apps personnalisées nécessitent Plus ; les apps publiques sont ouvertes)

Éditeur

Éditeur de Scripts dans l’admin

IDE local + Shopify CLI

Versioning

Aucun — modifications en direct

Compatible Git — contrôle de version complet

Tests

Manuel dans le checkout

Développement local avec shopify app dev, liens de prévisualisation

Déploiement

Cliquer sur « Enregistrer » dans l’admin

shopify app deploy depuis le terminal

Cibles

Articles, expédition, paiements

Remises, transformation du panier, validation, personnalisation de livraison, personnalisation de paiement, routage des commandes, contraintes de fulfillment, et plus

Le changement architectural est important. Les Scripts, c’était « retoucher du Ruby dans une zone de texte ». Les Functions, c’est « écrire une vraie application, la versionner, la tester localement, la déployer via un vrai pipeline CI ». La courbe d’apprentissage est plus raide. Mais c’est aussi la dernière migration que vous ferez pour la logique de checkout dans un avenir prévisible — les Functions sont l’engagement à long terme de Shopify, pas un palliatif comme l’étaient finalement les Scripts.

Associer vos Scripts au bon type de Function

Chaque Script que vous avez aujourd’hui correspond à une seule API Function. Voici le tableau de correspondance à garder sous les yeux.

Ancien type de Script

Ce qu’il faisait

Nouvelle API Function

Cible de la Function

Line Item Script

Appliquer des remises à des produits / clients / conditions de panier spécifiques

Cart & Checkout Discounts API

cart.lines.discounts.generate.run

Shipping Script (remise)

Livraison gratuite / remisée selon les règles du panier

Cart & Checkout Discounts API

cart.delivery-options.discounts.generate.run

Shipping Script (masquer / renommer / réordonner)

Masquer un tarif de livraison au-dessus de X $, renommer « Standard » en « Gratuit au-delà de 50 $ »

Delivery Customization API

cart.delivery-options.transform.run

Payment Script

Masquer PayPal pour le B2B, masquer le paiement à la livraison au-dessus de 500 $, réordonner les moyens

Payment Customization API

cart.payment-methods.transform.run

Script de modification du panier (rare)

Regrouper des produits, remplacer des line items

Cart Transform API

cart.transform.run

Script de blocage du checkout

Refuser le panier si le mélange de SKU est invalide

Cart & Checkout Validation API

cart.validations.generate.run

Si vous avez dix Scripts, vous construirez probablement trois à cinq Functions — plusieurs Scripts se regroupent souvent en une seule Function avec une logique de branchement plus propre.


Shopify Functions unifying discounts, delivery, and payment customizations

Prérequis : configurer votre environnement de développement local

Avant de scaffold une Function, vous devez installer trois éléments en local. Lancez ces vérifications dans votre terminal.

1. Node.js 18+

node --version
# Doit être >= 18.0.0

Si votre version est plus ancienne, installez-la via nvm ou téléchargez-la depuis nodejs.org.

2. Shopify CLI 3+

npm install -g @shopify/cli@latest
shopify version
# Devrait afficher 3.x ou plus

3. Chaîne d’outils Rust (uniquement si vous écrivez vos Functions en Rust)

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

Les Functions JavaScript n’ont pas besoin de Rust. Choisissez un langage pour votre équipe et tenez-vous-y — en utiliser deux ajoute une surcharge de maintenance.

4. Une boutique de développement

Connectez-vous à votre tableau de bord Partner et créez une nouvelle boutique de développement, ou utilisez-en une existante. Vous déploierez les Functions sur cette boutique avant de passer en production.

Scaffolder votre première Function

La CLI génère la majeure partie du boilerplate. Dans n’importe quel répertoire :

# Créez une nouvelle app Shopify (ignorez cette étape si vous en avez déjà une)
shopify app init my-checkout-functions
cd my-checkout-functions

# Générez une extension Function
shopify app generate extension

La CLI vous guide à travers les invites. Pour une Function de remise, vous choisiriez :

  • Type : Function

  • Template : discount (ou cart_checkout_validation, delivery_customization, payment_customization, etc.)

  • Langage : Rust ou JavaScript

  • Nom : quelque chose comme volume-discount-fn

Cela crée extensions/volume-discount-fn/ avec :

extensions/volume-discount-fn/
├── shopify.extension.toml      # Configuration de la Function cibles, build, version
├── src/
├── cart_lines_discounts_generate_run.graphql   # Requête d’entrée
└── cart_lines_discounts_generate_run.rs        # Logique de la Function
├── Cargo.toml                  # Dépendances Rust (Rust uniquement)
└── README.md

Les trois fichiers que vous modifierez constamment sont le .toml (configuration), le .graphql (entrée) et le .rs / .js (logique). C’est tout.

Tutoriel 1 : remplacer un Line Item Script (remise sur volume)

Supposons que votre ancien Script accordait 10 % de remise sur le sous-total de la commande lorsque le panier contenait 5 unités ou plus d’une collection spécifique. Voici l’équivalent en Function.

Étape 1.1 : la configuration (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"]

Étape 1.2 : la requête d’entrée (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
  }
}

Astuce : Les Functions ne voient que les données que vous interrogez. Gardez le GraphQL minimal — chaque champ que vous omettez signifie une exécution plus rapide et moins coûteuse.

Étape 1.3 : la logique (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> {
    // Quitter si la classe de remise ne correspond pas
    let has_order_discount = input
        .discount()
        .discount_classes()
        .contains(&schema::DiscountClass::Order);

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

    // Additionner les quantités des articles de la collection cible
    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![] });
    }

    // Appliquer 10 % de remise sur le sous-total de la commande
    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,
                }],
            },
        )],
    })
}

Étape 1.4 : tester, déployer, activer

# Développement local avec rechargement à chaud
shopify app dev

# Une fois prêt, déployez
shopify app deploy

# Dans le panneau GraphiQL qui s’ouvre (appuyez sur `g` dans le terminal de dev),
# créez la remise automatique qui utilise votre 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 }
  }
}

C’est tout. La Function est en ligne, versionnée, et remplace entièrement l’ancien Script.

Tutoriel 2 : remplacer un Shipping Script (masquer une méthode au-dessus d’un seuil de panier)

Script courant : « Masquer la livraison Express lorsque le sous-total du panier dépasse 500 $ afin d’éviter une expédition de nuit coûteuse sur les grosses commandes. » Voici la version Function en Delivery Customization.

Étape 2.1 : scaffold

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

Étape 2.2 : requête d’entrée (src/run.graphql)

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

Étape 2.3 : logique (src/run.js — variante JavaScript)

// @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 };
}

Étape 2.4 : activation via l’Admin (aucun GraphQL requis)

Les Delivery Customizations disposent aussi d’une interface d’administration intégrée. Après shopify app deploy :

  1. Allez dans Settings → Shipping and delivery

  2. Faites défiler jusqu’à la section Customizations en bas

  3. Cliquez sur Add customization → sélectionnez votre Function

  4. Enregistrez

La règle de masquage est active en production. Aucune mutation n’est nécessaire.


Shopify delivery customization Function hiding shipping option at checkout

Tutoriel 3 : remplacer un Payment Script (masquer le paiement à la livraison pour le B2B)

Ancien Script : « Masquer le paiement à la livraison pour tout client ayant le tag 'B2B'. » Voici la version Payment Customization.

Étape 3.1 : scaffold

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

Étape 3.2 : requête d’entrée

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

Étape 3.3 : logique (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 } }],
  };
}

Étape 3.4 : activation

Les Payment Customizations disposent aussi d’une interface d’administration sous Settings → Payments → Customizations. Même processus que pour la livraison — choisissez votre Function, enregistrez, terminé.

Puisque vous lisez ceci — un mot sur l’après-achat

Petite précision puisque c’est le blog de Revize. Revize gère ce que les Functions ne peuvent pas toucher — une fois qu’une commande est passée, les clients veulent ajouter un article, changer une taille, corriger l’adresse de livraison, appliquer une remise qu’ils ont oubliée. Les Functions vivent au checkout. Revize vit après le checkout. Les Functions décident de ce qui est autorisé dans le panier ; Revize permet à vos clients et à votre équipe support de modifier la commande ensuite sans passer par un cycle remboursement + recréation. Cela compte pour deux types de boutiques : celles qui ont suffisamment de volume de commandes pour que l’édition manuelle s’effondre (les opérateurs Plus, évidemment, mais aussi les boutiques Advanced à fort débit), et celles dont toute la marque repose sur l’expérience client — où un e-mail du type « désolé, nous ne pouvons pas modifier cela » tue les achats répétés.

Si votre plan de migration couvre Scripts → Functions mais que vous n’avez jamais réglé les modifications de commandes après achat, vous allez heurter le prochain mur « pourquoi est-ce si compliqué ? » dans environ trois semaines. Le guide de gestion des commandes que nous venons de publier décrit tout le plan de bataille post-checkout.

Retour à la migration.

Stratégie de test : le modèle du client balisé

Les Functions n’ont pas de « mode brouillon » que vous pouvez activer ou désactiver dans l’admin. La méthode professionnelle consiste à conditionner la nouvelle Function à un tag client, à faire fonctionner en parallèle l’ancien Script et la nouvelle Function, à vérifier qu’ils produisent une sortie identique pour les utilisateurs balisés, puis à basculer.

Étape 1 : taguez vos utilisateurs de test

Dans Customers, ajoutez le tag FN-TESTER à deux ou trois comptes internes.

Étape 2 : branchez la Function sur la présence du tag

// En haut de votre fonction run
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);  // Laisser passer vers le Script existant
}

// La nouvelle logique de la Function ne s’exécute que pour les utilisateurs balisés

Étape 3 : ajoutez hasAnyTag à votre requête d’entrée

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

Étape 4 : vérifiez dans le checkout

Connectez-vous en tant qu’utilisateur balisé, parcourez le checkout, confirmez que la Function se déclenche. Connectez-vous en tant qu’utilisateur non balisé, confirmez que l’ancien Script s’exécute toujours. Quand la parité tient pendant quelques jours, retirez la vérification du tag et laissez la Function s’exécuter pour tout le monde.

Étape 5 : dépubliez l’ancien Script

Allez dans Apps → Script Editor → [Your Script] → Unpublish. Une fois dépublié, la Function devient la seule source de vérité.

Un workflow de déploiement qui passe vraiment à l’échelle

Ne déployez pas éternellement depuis l’ordinateur portable d’un développeur. Une fois un ou deux Scripts migrés, mettez en place un vrai pipeline CI.

Le workflow minimal viable

# .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 }}

Générez le jeton Partner depuis votre tableau de bord Partner sous Settings → Tokens. Désormais, chaque fusion dans main déploie vos Functions. Fini les fils Slack du genre « Mike a-t-il déployé ça ? ».

Versioning et rollback

shopify app deploy crée un instantané versionné. Pour revenir en arrière :

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

Comparé aux Scripts — où le rollback voulait dire « se souvenir de l’ancien code et le recoller » — c’est le jour et la nuit.


Shopify Functions deployment pipeline across local staging and production environments

Ce que la plupart des équipes font mal

Après avoir accompagné des marchands Plus dans cette migration au cours de l’année écoulée, on retrouve toujours les cinq mêmes erreurs.

1. Traiter les Functions comme un portage Script 1:1. Ce n’est pas le cas. Une seule Function peut remplacer trois Scripts avec un branchement plus propre. Auditez vos Scripts comme un système avant de les réécrire.

2. Oublier les scopes de lecture. De nombreuses Functions ont besoin de read_customers, read_orders ou write_discounts. Ajoutez-les dans shopify.app.toml sous scopes et réautorisez l’app, sinon votre requête d’entrée renverra null.

3. Exécuter les Functions sur des clients non balisés sans test de parité. Même si votre code semble correct, les cas limites (panier vide, cartes-cadeaux, crédit boutique, brouillons B2B) révéleront des problèmes. Un déploiement progressif par tag vous coûte deux jours et vous évite une panne P1.

4. Sauter le Customizations Report. C’est le meilleur inventaire de ce qui tourne réellement. Ne migrez pas depuis la mémoire — migrez depuis le rapport.

5. Codifier en dur les IDs de collections et les tags clients. Utilisez la configuration de Function via des metafields si vous avez besoin de valeurs ajustables par le marchand. La CLI peut scaffold une configuration basée sur des metafields — voir la documentation Shopify sur la configuration des Functions.

Checklist de migration pour les 75 prochains jours

Un plan réaliste semaine par semaine pour arriver sereinement au 30 juin.

Semaine

Action

Semaine 1 (cette semaine)

Récupérez le Customizations Report. Inventoriez chaque Script. Décidez : Function, app publique ou suppression.

Semaines 2–3

Configurez l’environnement de développement local. Scaffold la première Function. Migrez le Script le plus simple (généralement une règle de masquage de paiement).

Semaines 4–6

Migrez les Scripts de remise. Ce sont eux qui prennent le plus de temps, car l’API Discounts est la plus riche. Testez minutieusement avec des tags.

Semaines 7–8

Migrez les Scripts d’expédition / livraison. Activez les Delivery Customizations via l’Admin.

Semaines 9–10

Mettez en place le pipeline CI. Déplacez tous les déploiements hors des ordinateurs portables des développeurs.

Semaine 11 (mi-juin)

Vérification finale de parité. Dépubliez tous les Scripts. Faites tourner la boutique uniquement sur les Functions pendant deux semaines.

30 juin

Le jour de la bascule arrive. Rien ne casse parce que vous avez terminé tôt.

Si vous commencez cette semaine, vous avez de la marge. Si vous commencez en juin, vous n’en avez pas.


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

Questions fréquemment posées

Ai-je besoin de Shopify Plus pour utiliser les Functions ?

Les Functions personnalisées nécessitent Shopify Plus, mais les Functions d’apps publiques fonctionnent sur tous les plans. Si vous n’êtes pas sur Plus, vous avez deux options : installer depuis le Shopify App Store une app publique qui fournit la Function pour vous, ou passer à Plus pour écrire vos propres Functions personnalisées. La plupart des grands marchands qui avaient des Scripts étaient déjà sur Plus, donc cela ne change que rarement quoi que ce soit en pratique.

Puis-je écrire des Functions en TypeScript ?

Oui — TypeScript est entièrement pris en charge et la CLI le scaffold pour vous. Quand vous exécutez shopify app generate extension et choisissez « JavaScript », le projet généré inclut des déclarations de types depuis import("../generated/api"). Vous pouvez convertir les fichiers en .ts et ajouter un tsconfig.json si vous préférez. Le résultat compilé (WASM) est identique quel que soit le langage source.

À quelle vitesse s’exécutent les Functions par rapport aux Scripts ?

Les Functions s’exécutent généralement en moins de 5 ms — nettement plus vite que les Scripts Ruby. Comme elles sont compilées en WebAssembly et tournent dans un runtime très serré, Shopify impose une limite d’exécution de 5 ms. Si votre Function la dépasse, l’opération est ignorée et votre Function ne renvoie aucune opération. En pratique, une Function bien écrite utilise 1 à 2 ms. Le plafond de performance est bien plus élevé que celui des Scripts.

Une Function peut-elle appeler une API externe ?

Non — les Functions ne peuvent pas effectuer de requêtes réseau. Elles font uniquement du calcul pur : données d’entrée du panier → opérations de sortie. Si vous avez besoin de données externes (une recherche CRM, une vérification d’inventaire en temps réel), vous devrez soit stocker ces données à l’avance dans des metafields, soit utiliser une autre surface (App Proxy, webhooks, Cart Transform avec recherche côté backend). C’est la raison la plus courante pour laquelle les équipes doivent repenser la solution plutôt que simplement porter le code.

Quelle est la différence entre Cart Transform et Discounts ?

Les Discounts appliquent des changements de prix ; Cart Transform modifie le contenu du panier. Utilisez l’API Discounts pour appliquer -10 %, la livraison gratuite ou un BOGO. Utilisez Cart Transform pour regrouper deux produits en une seule ligne, ou découper un variant en plusieurs. Beaucoup d’anciens Scripts mélangeaient les deux sujets — lors de la migration, séparez-les en deux Functions.

Comment tester une Function localement sans boutique de développement ?

Vous pouvez exécuter des tests unitaires avec cargo test (Rust) ou npm test (JS), mais le test d’intégration complet nécessite une boutique de développement. La CLI fournit shopify app function run, qui exécute votre Function sur un fichier d’entrée exemple — utile pour itérer rapidement. Mais pour confirmer le comportement du checkout de bout en bout, il vous faut une vraie boutique avec un vrai panier.

Puis-je avoir plusieurs Functions du même type ?

Oui — Shopify prend en charge plusieurs Functions par cible, et elles s’exécutent dans un ordre déterministe. Pour les remises, l’ordre est régi par les règles de cumul de remises de Shopify. Pour les Delivery et Payment Customizations, vous pouvez chaîner des Functions, mais chaque sortie alimente la suivante. La plupart des équipes utilisent une Function par type pour simplifier.

Que devient mon Script après le déploiement de la Function ?

Les deux s’exécutent en parallèle jusqu’à ce que vous dépubliiez le Script dans Apps → Script Editor. C’est intentionnel — cela vous donne la fenêtre de test en parallèle. Après avoir vérifié que la Function fonctionne, dépubliez manuellement le Script. Après le 30 juin 2026, tous les Scripts cessent de s’exécuter, que vous les ayez dépubliés ou non.

La migration affectera-t-elle mon SEO ou mon thème ?

Non — les Functions s’exécutent côté serveur au checkout et ne touchent jamais votre thème ni vos pages produit. Elles ne modifient que les remises, les options d’expédition et les moyens de paiement au checkout. Votre vitrine, vos templates produit et votre SEO restent totalement intacts.

Comment migrer un Script qui utilise Input.line_items avec des propriétés personnalisées ?

Les propriétés personnalisées sont accessibles via le champ attribute sur les lignes de panier dans l’entrée GraphQL. Ajoutez attribute(key: "your-key") { value } à l’intérieur de la sélection lines. La Function les lit de la même manière que les Scripts lisaient les propriétés de line item — simplement via GraphQL au lieu d’appels de méthodes Ruby.

Qu’en est-il des analytics et des tags de commande ? Les Functions peuvent-elles écrire des données ?

Les Functions ne peuvent pas écrire de tags de commande ni déclencher elles-mêmes des webhooks — elles ne renvoient que des opérations sur le panier actuel. Pour le tagging ou les workflows en aval, utilisez Shopify Flow déclenché par l’événement de création de commande. De nombreux marchands combinent une Function (pour la remise) avec un Flow (pour tagger la commande avec « VOLUME-DISCOUNT-APPLIED »).

Existe-t-il une app publique que je peux installer au lieu de construire une Function personnalisée ?

Oui — le Shopify App Store propose des dizaines d’apps qui encapsulent des Functions pour les cas d’usage courants. Cherchez « discount function », « delivery customization » ou « payment customization ». Pour des cas simples (remises sur volume, masquage de moyens de paiement par tag, livraison gratuite au-dessus de X), une app existante peut vous faire gagner des jours de travail. Réservez les Functions personnalisées à une logique réellement unique à votre activité.

Que se passe-t-il si je rate la date limite du 30 juin ?

Le Script cesse de s’exécuter — il n’y a ni repli, ni délai de grâce, ni prolongation. Ce que faisait le Script (la remise, le tarif de livraison masqué, le moyen de paiement bloqué) revient au comportement par défaut à minuit UTC le 1er juillet. Si votre activité dépend de cette logique, prévoyez d’être en ligne bien avant cette date. La migration prend plus de temps que la plupart des équipes ne l’estiment, surtout avec les tests de parité.

Puis-je supprimer complètement l’application Script Editor ?

Vous pouvez la désinstaller après le 30 juin 2026, mais Shopify la supprimera probablement automatiquement. Une fois les Scripts arrêtés, l’éditeur n’a plus d’utilité. Vous pouvez aussi dépublier tous les Scripts maintenant et désinstaller l’app immédiatement si vous avez terminé la migration — vos Functions sont indépendantes.

Que faire cette semaine

Ne lisez pas cet article pour fermer ensuite l’onglet. Faites ces quatre choses dans les sept prochains jours.

1. Récupérez le Customizations Report. Allez dans Settings → Checkout → Customizations Report. Exportez-le. C’est votre backlog de migration.

2. Configurez votre environnement de développement. Installez Node 18+, Shopify CLI et Rust (le cas échéant). Vérifiez que shopify version fonctionne. Temps total : 30 minutes.

3. Scaffold et expédiez une toute petite Function sur une boutique de développement. Prenez le Script le plus simple que vous avez — généralement une règle de masquage de paiement. Migrez-le de bout en bout. Même s’il n’arrive jamais en production, vous aurez validé la chaîne d’outils.

4. Réservez du temps dans le calendrier pour les huit prochaines semaines. Les migrations ne se font pas dans les moments libres entre deux sprints. Bloquez un créneau récurrent — par exemple tous les mardis et jeudis après-midi — et traitez-le comme une release.

D’après les équipes que nous avons vues migrer, le schéma est toujours le même : deux semaines d’hésitation, trois semaines de vrai travail, une semaine de nettoyage. Cela fait six semaines. Vous en avez dix. La marge existe — utilisez-la pour les revues de code et l’assurance qualité, pas pour repousser le démarrage.

Et une fois votre logique de checkout réglée, la prochaine chose que la plupart des équipes traitent est l’après-achat — changements d’adresse client, échanges, ajouts de remises après la commande. Si cela fait partie de votre feuille de route (et cela devrait l’être, que vous soyez un opérateur Plus à gros volume ou une boutique Advanced centrée sur l’expérience client), Revize est sur le Shopify App Store et fonctionne aux côtés de chaque Function que vous construirez ici.

Ressources

Articles associés

Repensez votre boutique Shopify. Misez sur l’expérience client.

© Copyright 2024, Tous droits réservés

Repensez votre boutique Shopify. Misez sur l’expérience client.

© Copyright 2024, Tous droits réservés

Repensez votre boutique Shopify. Misez sur l’expérience client.

© Copyright 2024, Tous droits réservés

Repensez votre boutique Shopify. Misez sur l’expérience client.

© Copyright 2024, Tous droits réservés

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: Deadline, Migration, and What's Broken How to Let Customers Cancel Orders on Shopify Shopify Legacy Customer Accounts Are Deprecated 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 Shopify AI Toolkit Guide 2026: Agents, MCP, and UCP Explained Shopify Sidekick vs Your Agency: The 2026 Scorecard for Plus Stores Shopify B2B 2026 Complete Guide Shopify Order Management Guide 2026 Shopify Advanced to Plus 2026 Migration Playbook