Migration de Shopify Scripts vers Functions : tutoriel de code 2026
Migration de Shopify Scripts vers Functions : tutoriel de code 2026
Migration de Shopify Scripts vers Functions : tutoriel de code 2026

Nous sommes le 16 avril 2026. Hier — le 15 avril — Shopify a définitivement verrouillé le Script Editor. Vous ne pouvez plus créer ni publier de nouveau Script. L'arrêt de l'exécution intervient dans 75 jours, le 30 juin 2026.
Si vous êtes un développeur Shopify Plus — ou l'agence qui gère une boutique Plus — et que vous avez repoussé cette migration au « prochain sprint » ces douze derniers mois, vous avez un problème. Pas un problème cosmétique. Un problème du type « votre tunnel de paiement plante à minuit le 1er juillet ». La plupart des boutiques Plus ont accumulé entre 5 et 20 Scripts au fil des ans, chacun gérant silencieusement une règle de réduction, un masquage de livraison ou une passerelle de paiement que personne ne se souvient avoir codée.
Ce guide est le manuel technique de migration que nous aurions aimé avoir en janvier. Il traite du code réel, pas seulement de la stratégie. À la fin de votre lecture, vous saurez comment échafauder une Function avec la Shopify CLI, écrire la logique en Rust ou JavaScript pour les réductions, les personnalisations de livraison et de paiement, la tester en toute sécurité sur un sous-ensemble de clients ciblé, et la déployer en production sans perturber votre checkout actuel.
Débarrassons votre boutique des Scripts et installons-y les Functions.

Réponse rapide : Scripts → Functions en 60 secondes
La migration en un paragraphe : Les Shopify Scripts (code Ruby dans le Script Editor, réservés à Plus) sont remplacés par les Shopify Functions (modules WebAssembly écrits en Rust ou JavaScript, disponibles pour tous les forfaits). Vous générez une Function avec
shopify app generate extension, écrivez une requêterun.graphqlqui récupère les données de panier nécessaires, écrivez un fichierrun.rsourun.jsqui renvoie les opérations (réductions, modes de livraison masqués, etc.), puis déployez avecshopify app deployet l'activez via l'Admin ou une mutation GraphQL. Les Functions s'exécutent sous forme de WASM compilé avec une latence inférieure à 5 ms, fonctionnent sur tous les forfaits et constituent l'unique voie de personnalisation prise en charge par Shopify à l'avenir.
Ce qui change réellement le 30 juin
Avant de toucher au code, actons les dates. Il y en a deux, et toutes deux sont cruciales.
Date | Événement | Action requise |
|---|---|---|
15 avril 2026 (passé) | Script Editor en lecture seule. Aucun nouveau Script. Aucune modification 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. Définitivement. | Votre Function de remplacement doit être active 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 elle ne l'est pas — et chaque panier concerné appliquera par défaut les tarifs standards, les frais de livraison de base et l'ensemble des modes de paiement activés. Pas de demi-mesure. Le Script s'exécute ou ne s'exécute pas, et après le 30 juin, il ne s'exécutera plus.
Astuce : Allez dans
Settings → Checkout → Customizations Reportdans votre admin Shopify. Vous y trouverez la liste de chaque Script actif sur votre boutique, son rôle et le type de Function de remplacement recommandé. Commencez par là.
Functions vs Scripts : Ce qui a réellement changé
Critère | Shopify Scripts (obsolète) | Shopify Functions (remplacement) |
|---|---|---|
Langage | Ruby DSL (propre à Shopify) | Rust, JavaScript, TypeScript |
Environnement d'exécution | Ruby sandboxé sur l'infrastructure Shopify | WebAssembly (WASM) — exécution < 5ms |
Forfaits compatibles | Plus uniquement | Tous les forfaits (les apps personnalisées nécessitent Plus ; les apps publiques sont ouvertes) |
Éditeur | Script Editor intégré à l'admin | IDE local + Shopify CLI |
Gestion des versions | Aucune — modifications en direct | Compatible Git — contrôle de version complet |
Tests | Manuels dans le checkout | Développement local avec |
Déploiement | Clic sur "Enregistrer" dans l'admin |
|
Cibles | Articles du panier, expédition, paiements | Discounts, Cart Transform, Validation, Delivery Customization, Payment Customization, Order Routing, Fulfillment Constraints, et plus |
Le changement d'architecture est fondamental. Les Scripts consistaient à « bricoler du Ruby dans une zone de texte ». Les Functions consistent à « écrire une véritable application, la versionner, la tester localement, la déployer via un pipeline CI digne de ce nom ». La courbe d'apprentissage est plus raide. C'est aussi la dernière migration que vous aurez à faire pour la logique de checkout dans un avenir prévisible — les Functions représentent l'engagement à long terme de Shopify, contrairement aux Scripts qui se sont avérés être une solution temporaire.
Associer vos Scripts au bon type de Function
Chaque Script actuel correspond à exactement une API de Function. Voici la table de correspondance à garder sous les yeux.
Ancien type de Script | Rôle | Nouvelle API de Function | Cible (Target) |
|---|---|---|---|
Line Item Script | Appliquer des remises à des produits / clients / conditions de panier spécifiques | Cart & Checkout Discounts API |
|
Shipping Script (remise) | Livraison gratuite ou réduite selon des règles de panier | Cart & Checkout Discounts API |
|
Shipping Script (masquer / renommer / réordonner) | Masquer un tarif au-dessus de X $, renommer "Standard" en "Gratuit dès 50 $" | Delivery Customization API |
|
Payment Script | Masquer PayPal pour le B2B, masquer le paiement à la livraison au-dessus de 500 $, réordonner les modes de paiement | Payment Customization API |
|
Script de modification de panier (rare) | Créer des lots de produits, remplacer des articles | Cart Transform API |
|
Script de blocage du checkout | Refuser le panier si la combinaison de SKU est non valide | Cart & Checkout Validation API |
|
Si vous avez dix Scripts, vous développerez probablement entre trois et cinq Functions — plusieurs Scripts se résument souvent à une seule Function dotée d'une logique de branchement plus propre.

Prérequis : Configurer votre environnement de développement local
Avant de générer une Function, vous devez installer trois outils en local. Exécutez 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 la version est plus ancienne, installez-la via nvm ou téléchargez-la sur nodejs.org.
2. Shopify CLI 3+
npm install -g @shopify/cli@latest shopify version # Doit afficher 3.x ou plus
npm install -g @shopify/cli@latest shopify version # Doit afficher 3.x ou plus
3. Toolchain 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 en JavaScript n'ont pas besoin de Rust. Choisissez un langage pour votre équipe et tenez-vous-y — mélanger les deux ajoute des coûts 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 y déploierez vos Functions avant de les passer en production.
Générer votre première Function
La CLI s'occupe de l'essentiel du code de base. Dans n'importe quel répertoire :
# Créer une nouvelle application Shopify (ignorez si vous en avez déjà une) shopify app init my-checkout-functions cd my-checkout-functions # Générer une extension de type Function shopify app generate extension
# Créer une nouvelle application Shopify (ignorez si vous en avez déjà une) shopify app init my-checkout-functions cd my-checkout-functions # Générer une extension de type Function shopify app generate extension
La CLI vous guide à travers différentes questions. Pour une Function de réduction, vous choisiriez :
Type : Function
Modèle :
discount(oucart_checkout_validation,delivery_customization,payment_customization, etc.)Langage : Rust ou JavaScript
Nom : par exemple
volume-discount-fn
Cela crée le répertoire extensions/volume-discount-fn/ contenant :
extensions/volume-discount-fn/ ├── shopify.extension.toml # Config 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 # Config 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 en permanence sont le .toml (config), 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 appliquait une remise de 10 % sur le sous-total de la commande dès que le panier contenait au moins 5 articles d'une collection spécifique. Voici l'équivalent sous forme de 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 demandez. Limitez le GraphQL au strict minimum — chaque champ ignoré garantit 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> { // Arrêter 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![] }); } // Sommer les quantités d'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 réduction 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> { // Arrêter 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![] }); } // Sommer les quantités d'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 réduction 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 # Lorsque vous êtes 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 # Lorsque vous êtes 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 active, versionnée et remplace définitivement l'ancien Script.
Tutoriel 2 : Remplacer un Shipping Script (Masquer un mode de livraison selon le montant du panier)
Un Script classique : « Masquer la livraison Express lorsque le sous-total du panier dépasse 500 $ pour éviter des frais d'envoi de nuit exorbitants sur de grosses commandes. » Voici la version Delivery Customization avec une Function.
Étape 2.1 : Générer l'extension
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 : Activer via l'Admin (sans GraphQL)
Les Delivery Customizations disposent d'une interface d'administration intégrée. Après l'exécution de shopify app deploy :
Allez dans Settings → Shipping and delivery
Faites défiler jusqu'à la section Customizations tout en bas
Cliquez sur Add customization → sélectionnez votre Function
Enregistrez
La règle de masquage est active en production. Aucune mutation requise.

Tutoriel 3 : Remplacer un Payment Script (Masquer le paiement à la livraison pour le B2B)
Ancien Script : « Masquer le paiement à la livraison (COD) pour tout client doté du tag 'B2B'. » Voici la version Payment Customization.
Étape 3.1 : Générer l'extension
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 : Activer
Les Payment Customizations ont également une interface d'administration dans Settings → Payments → Customizations. Même processus que pour la livraison — sélectionnez votre Function, enregistrez, terminé.
Puisque vous lisez ceci — Un mot sur le post-achat
Une mise au point rapide puisque vous êtes sur le blog de Revize. Revize gère ce que les Functions ne peuvent pas toucher — une fois la commande passée, les clients veulent ajouter un article, modifier une taille, corriger l'adresse de livraison ou appliquer un code promo oublié. Les Functions interviennent lors du paiement. Revize intervient après. Les Functions déterminent ce qui est autorisé dans le panier ; Revize offre à vos clients et à votre équipe de support la possibilité de modifier la commande a posteriori sans passer par un cycle d'annulation et de recréation. C'est capital pour deux types de boutiques : celles qui ont un volume de commandes tel que l'édition manuelle devient impossible (les opérateurs Plus, par définition, mais aussi les boutiques Advanced à fort trafic), et celles dont l'image de marque repose sur l'expérience client — où un e-mail indiquant « désolé, nous ne pouvons pas modifier cela » détruit la fidélisation.
Si votre plan de migration couvre Scripts → Functions mais que vous n'avez pas encore résolu la gestion des modifications post-achat, vous vous heurterez au prochain obstacle technique d'ici trois semaines. Le guide de gestion des commandes que nous venons de publier détaille l'ensemble de la stratégie post-paiement.
Retour à la migration.
Stratégie de test : La méthode du tag client
Les Functions ne possèdent pas de « mode brouillon » activable dans l'admin. La bonne pratique professionnelle consiste à conditionner la nouvelle Function à la présence d'un tag client, à exécuter l'ancien Script et la nouvelle Function en parallèle, à vérifier qu'ils produisent des résultats identiques pour les utilisateurs taggués, puis à effectuer la bascule complète.
Étape 1 : Tagger vos utilisateurs de test
Dans la section Customers, ajoutez le tag FN-TESTER à deux ou trois comptes internes.
Étape 2 : Conditionner la Function à la présence du tag
// Au début 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 l'exécution à l'ancien Script } // La logique de la nouvelle Function s'exécute uniquement pour les testeurs
// Au début 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 l'exécution à l'ancien Script } // La logique de la nouvelle Function s'exécute uniquement pour les testeurs
Étape 3 : Ajouter hasAnyTag à votre requête d'entrée
cart { buyerIdentity { customer { hasAnyTag(tags: ["FN-TESTER"]) } } }
cart { buyerIdentity { customer { hasAnyTag(tags: ["FN-TESTER"]) } } }
Étape 4 : Vérifier dans le checkout
Connectez-vous avec un compte taggué, passez une commande de test, validez que la Function se déclenche. Connectez-vous avec un compte non taggué, validez que l'ancien Script s'exécute toujours. Après quelques jours sans anomalie, retirez la vérification du tag pour appliquer la Function à tous.
Étape 5 : Retirer l'ancien Script
Allez dans Apps → Script Editor → [Votre Script] → Unpublish. Une fois dépublié, la Function devient l'unique source de vérité.
Un flux de déploiement véritablement structuré
Ne déployez pas indéfiniment depuis la machine d'un développeur. Dès que vous avez migré un ou deux Scripts, configurez un véritable 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 token partenaire depuis votre tableau de bord Partner dans Settings → Tokens. Désormais, chaque fusion vers main déploie vos Functions. Fini les discussions Slack pour savoir qui a déployé la dernière version.
Gestion des versions et retour arrière
La commande 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 retour arrière consistait à retrouver l'ancien code manuellement pour le recoller — c'est le jour et la nuit.

Les erreurs les plus fréquentes commises par les équipes
Après avoir accompagné de nombreux marchands Plus dans cette migration l'an dernier, les cinq mêmes erreurs reviennent systématiquement.
1. Traiter les Functions comme un simple portage de Script individuel. Ce n'est pas le cas. Une seule Function peut remplacer trois Scripts grâce à une logique de branchement plus saine. Analysez vos Scripts de manière globale avant de réécrire le code.
2. Oublier les habilitations d'API (scopes d'accès). Beaucoup de Functions nécessitent read_customers, read_orders ou write_discounts. Ajoutez-les dans shopify.app.toml sous la clé scopes et autorisez à nouveau l'application, sans quoi votre requête d'entrée renverra des données nulles.
3. Lancer les Functions pour tous les clients sans test de parité préalable. Même si votre code vous semble correct, des cas particuliers (paniers vides, cartes-cadeaux, avoirs, brouillons de commandes B2B) feront émerger des anomalies. Un déploiement progressif par tag vous évite des pannes bloquantes en production.
4. Faire l'impasse sur le Customizations Report. C'est la cartographie la plus précise de vos personnalisations actives. Ne vous fiez pas à votre mémoire, fiez-vous au rapport.
5. Hardcoder les identifiants de collections et les tags clients. Utilisez la configuration de Function via les metafields si vous avez besoin de valeurs ajustables par les marchands. La CLI permet de générer des configurations basées sur les metafields — consultez la documentation de Shopify à ce sujet.
Feuille de route de migration pour les 75 prochains jours
Un calendrier réaliste semaine par semaine pour aborder le 30 juin sereinement.
Semaines | Action |
|---|---|
Semaine 1 (cette semaine) | Générez le Customizations Report. Listez chaque Script. Choisissez : Function, application publique ou suppression. |
Semaines 2 et 3 | Configurez l'environnement de dev local. Créez 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 liés aux remises. Ce sont les plus longs à traiter en raison de la richesse de l'API Discounts. Testez minutieusement par tag. |
Semaines 7 et 8 | Migrez les Scripts liés à la livraison. Activez les Delivery Customizations dans l'admin. |
Semaines 9 et 10 | Configurez le pipeline CI. Automatisez les déploiements hors des machines locales des développeurs. |
Semaine 11 (mi-juin) | Validation finale de la parité. Désactivez tous les Scripts. Faites tourner la boutique uniquement avec les Functions pendant deux semaines. |
30 juin | Date de fin d'exécution. Aucune interruption de service car vous avez terminé en avance. |
En commençant cette semaine, vous conservez une marge de sécurité. En commençant en juin, vous n'en aurez pas.

Foire Aux Questions
Dois-je posséder un forfait Shopify Plus pour utiliser les Functions ?
Les Functions personnalisées nécessitent Shopify Plus, mais les Functions issues d'applications publiques fonctionnent sur tous les forfaits. Si vous n'êtes pas sur Plus, deux solutions s'offrent à vous : installer une application publique depuis le Shopify App Store qui intègre la Function requise, ou passer à Plus pour concevoir vos propres Functions personnalisées. La plupart des marchands d'envergure utilisant des Scripts disposent déjà de Plus.
Puis-je écrire des Functions en TypeScript ?
Oui — TypeScript est pleinement pris en charge et la CLI configure le projet pour vous. Lorsque vous lancez shopify app generate extension et optez pour « JavaScript », le projet généré inclut les déclarations de types de import("../generated/api"). Vous pouvez renommer vos fichiers en .ts et ajouter un fichier tsconfig.json. Le build final (WASM) sera identique.
Quelle est la rapidité des Functions par rapport aux Scripts ?
Les Functions s'exécutent généralement en moins de 5 ms — soit beaucoup plus rapidement que les Scripts Ruby. Étant compilées en WebAssembly et exécutées dans un environnement optimisé, un budget d'exécution de 5 ms est imposé par Shopify. Si votre Function le dépasse, l'opération est abandonnée. En pratique, une Function bien conçue requiert 1 à 2 ms.
Une Function peut-elle interroger une API externe ?
Non — les Functions ne peuvent effectuer aucun appel réseau. Ce sont des briques de calcul pur : elles reçoivent des données de panier en entrée et renvoient des opérations en sortie. Si vous devez exploiter des données externes (CRM, stock en temps réel), stockez-les préalablement dans des metafields, ou utilisez un autre mécanisme (App Proxy, webhooks, Cart Transform avec appel back-end).
Quelle est la différence entre Cart Transform et les Discounts ?
Les Discounts appliquent des réductions tarifaires ; Cart Transform modifie le contenu même du panier. Utilisez l'API Discounts pour appliquer un code, une remise de 10 %, la livraison gratuite ou du type X achetés Y offerts. Utilisez Cart Transform pour regrouper deux produits sous une ligne unique, ou décomposer une variante en plusieurs éléments. Séparez bien ces deux fonctions lors de votre migration.
Comment tester une Function en local 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 exige une boutique de dev. La CLI propose la commande shopify app function run pour exécuter votre Function face à un fichier d'entrée simulé. Pour valider l'expérience dans le checkout réel, une boutique est incontournable.
Puis-je avoir plusieurs Functions du même type actives simultanément ?
Oui — Shopify autorise plusieurs Functions par cible, exécutées selon un ordre déterminé. Pour les remises, la priorité dépend des règles de cumul de Shopify. Pour les personnalisations de livraison et de paiement, les outputs s'enchaînent. Utiliser une seule Function par cible simplifie grandement la maintenance.
Qu'advient-il de mon Script une fois la Function déployée ?
Les deux s'exécutent en parallèle jusqu'à ce que vous archiviez le Script dans Apps → Script Editor. Ce fonctionnement est voulu pour vous permettre de réaliser des phases de tests parallèles en production. Une fois les tests concluants, désactivez le Script. Au-delà du 30 juin 2026, de toute façon, aucun Script ne fonctionnera plus.
Cette migration aura-t-elle un impact sur mon SEO ou mon thème ?
Non — les Functions s'exécutent côté serveur lors du passage en caisse et n'interfèrent jamais avec votre thème ou vos pages produits. Elles ciblent uniquement les réductions, les choix de livraison et les paiements à l'étape finale. Votre site d'e-commerce et votre référencement ne subissent aucun changement.
Comment migrer un Script qui exploite Input.line_items avec des propriétés personnalisées ?
Ces propriétés personnalisées sont accessibles via le champ attribute des lignes de panier de la requête GraphQL. Ajoutez attribute(key: "votre-clef") { value } au sein de la sélection de lignes. La Function lira cette valeur de la même manière que vos Scripts Ruby lisaient les attributs d'articles.
Qu'en est-il des données analytiques et des tags de commande ? Les Functions peuvent-elles en écrire ?
Les Functions ne peuvent pas appliquer de tags aux commandes ni déclencher de webhooks — elles gèrent exclusivement le panier actif. Pour du taggage ou d'autres flux en aval, utilisez Shopify Flow déclenché par l'événement de création de commande. Associez par exemple une Function pour appliquer la remise et un workflow Flow pour tagguer la commande finale.
Existe-t-il une application publique prête à l'emploi si je ne souhaite pas développer de Function personnalisée ?
Oui — le Shopify App Store propose des dizaines d'applications qui encapsulent les Functions pour les cas d'usage récurrents. Cherchez des termes comme "discount function" ou "payment customization". Pour des stratégies classiques (remise sur quantité, masquer des paiements par tag, livraison gratuite dès X $), cela peut vous éviter plusieurs jours de développement. Réservez le sur-mesure aux règles métiers uniques.
Que se passe-t-il si je dépasse la date limite du 30 juin ?
Le Script s'arrête net — aucun délai de grâce, aucune prolongation ne sera accordée. Tout mécanisme géré par le Script (réduction, frais de port modifiés, mode de paiement masqué) reprendra son comportement par défaut le 1er juillet à minuit UTC. Prévoyez une mise en ligne finale bien avant cette date.
Puis-je supprimer définitivement l'application Script Editor ?
Vous pourrez la désinstaller après le 30 juin 2026, sachant que Shopify devrait la retirer automatiquement. Une fois l'échéance passée, cet éditeur n'aura plus d'utilité. Si votre migration est validée en amont, vous pouvez la supprimer dès maintenant ; vos Functions s'exécutent de manière autonome.
Actions prioritaires pour cette semaine
Ne remettez pas à plus tard. Initiez la transition en accomplissant ces quatre tâches d'ici sept jours.
1. Exportez le Customizations Report. Rendez-vous sur Settings → Checkout → Customizations Report et téléchargez-le. Ce document constitue votre cahier des charges de migration.
2. Installez votre environnement de développement. Mettez en place Node 18+, la CLI Shopify et Rust (si requis). Vérifiez le bon fonctionnement de shopify version. Durée estimée : 30 minutes.
3. Déployez une micro-Function sur une boutique de développement. Sélectionnez le Script le moins complexe (par exemple, le masquage d'une option de paiement). Réalisez sa migration de bout en bout pour éprouver votre pipeline d'outils, même si elle n'est pas déployée immédiatement.
4. Planifiez des plages de travail dans les huit prochaines semaines. Une migration réussie demande du temps dédié. Réservez des créneaux de travail récurrents (par exemple deux après-midis par semaine) et traitez ces phases comme des jalons de livraison majeurs.
Les retours d'expérience montrent souvent le même schéma : deux semaines de latence, trois semaines de développement et une semaine d'ajustements. Cela représente un total de six semaines. Il vous en reste dix. Profitez de cette avance pour soigner vos revues de code et vos étapes de recette.
Une fois votre logique de paiement convertie, l'étape suivante pour la majorité des équipes consiste à optimiser les processus post-achat (corrections d'adresses, ajouts de remises après commande). Si vous intégrez cela à votre feuille de route, sachez que l'application Revize est disponible sur le Shopify App Store et opère aux côtés des nouvelles Functions que vous concevez.
Ressources
Articles connexes
Nous sommes le 16 avril 2026. Hier — le 15 avril — Shopify a définitivement verrouillé le Script Editor. Vous ne pouvez plus créer ni publier de nouveau Script. L'arrêt de l'exécution intervient dans 75 jours, le 30 juin 2026.
Si vous êtes un développeur Shopify Plus — ou l'agence qui gère une boutique Plus — et que vous avez repoussé cette migration au « prochain sprint » ces douze derniers mois, vous avez un problème. Pas un problème cosmétique. Un problème du type « votre tunnel de paiement plante à minuit le 1er juillet ». La plupart des boutiques Plus ont accumulé entre 5 et 20 Scripts au fil des ans, chacun gérant silencieusement une règle de réduction, un masquage de livraison ou une passerelle de paiement que personne ne se souvient avoir codée.
Ce guide est le manuel technique de migration que nous aurions aimé avoir en janvier. Il traite du code réel, pas seulement de la stratégie. À la fin de votre lecture, vous saurez comment échafauder une Function avec la Shopify CLI, écrire la logique en Rust ou JavaScript pour les réductions, les personnalisations de livraison et de paiement, la tester en toute sécurité sur un sous-ensemble de clients ciblé, et la déployer en production sans perturber votre checkout actuel.
Débarrassons votre boutique des Scripts et installons-y les Functions.

Réponse rapide : Scripts → Functions en 60 secondes
La migration en un paragraphe : Les Shopify Scripts (code Ruby dans le Script Editor, réservés à Plus) sont remplacés par les Shopify Functions (modules WebAssembly écrits en Rust ou JavaScript, disponibles pour tous les forfaits). Vous générez une Function avec
shopify app generate extension, écrivez une requêterun.graphqlqui récupère les données de panier nécessaires, écrivez un fichierrun.rsourun.jsqui renvoie les opérations (réductions, modes de livraison masqués, etc.), puis déployez avecshopify app deployet l'activez via l'Admin ou une mutation GraphQL. Les Functions s'exécutent sous forme de WASM compilé avec une latence inférieure à 5 ms, fonctionnent sur tous les forfaits et constituent l'unique voie de personnalisation prise en charge par Shopify à l'avenir.
Ce qui change réellement le 30 juin
Avant de toucher au code, actons les dates. Il y en a deux, et toutes deux sont cruciales.
Date | Événement | Action requise |
|---|---|---|
15 avril 2026 (passé) | Script Editor en lecture seule. Aucun nouveau Script. Aucune modification 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. Définitivement. | Votre Function de remplacement doit être active 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 elle ne l'est pas — et chaque panier concerné appliquera par défaut les tarifs standards, les frais de livraison de base et l'ensemble des modes de paiement activés. Pas de demi-mesure. Le Script s'exécute ou ne s'exécute pas, et après le 30 juin, il ne s'exécutera plus.
Astuce : Allez dans
Settings → Checkout → Customizations Reportdans votre admin Shopify. Vous y trouverez la liste de chaque Script actif sur votre boutique, son rôle et le type de Function de remplacement recommandé. Commencez par là.
Functions vs Scripts : Ce qui a réellement changé
Critère | Shopify Scripts (obsolète) | Shopify Functions (remplacement) |
|---|---|---|
Langage | Ruby DSL (propre à Shopify) | Rust, JavaScript, TypeScript |
Environnement d'exécution | Ruby sandboxé sur l'infrastructure Shopify | WebAssembly (WASM) — exécution < 5ms |
Forfaits compatibles | Plus uniquement | Tous les forfaits (les apps personnalisées nécessitent Plus ; les apps publiques sont ouvertes) |
Éditeur | Script Editor intégré à l'admin | IDE local + Shopify CLI |
Gestion des versions | Aucune — modifications en direct | Compatible Git — contrôle de version complet |
Tests | Manuels dans le checkout | Développement local avec |
Déploiement | Clic sur "Enregistrer" dans l'admin |
|
Cibles | Articles du panier, expédition, paiements | Discounts, Cart Transform, Validation, Delivery Customization, Payment Customization, Order Routing, Fulfillment Constraints, et plus |
Le changement d'architecture est fondamental. Les Scripts consistaient à « bricoler du Ruby dans une zone de texte ». Les Functions consistent à « écrire une véritable application, la versionner, la tester localement, la déployer via un pipeline CI digne de ce nom ». La courbe d'apprentissage est plus raide. C'est aussi la dernière migration que vous aurez à faire pour la logique de checkout dans un avenir prévisible — les Functions représentent l'engagement à long terme de Shopify, contrairement aux Scripts qui se sont avérés être une solution temporaire.
Associer vos Scripts au bon type de Function
Chaque Script actuel correspond à exactement une API de Function. Voici la table de correspondance à garder sous les yeux.
Ancien type de Script | Rôle | Nouvelle API de Function | Cible (Target) |
|---|---|---|---|
Line Item Script | Appliquer des remises à des produits / clients / conditions de panier spécifiques | Cart & Checkout Discounts API |
|
Shipping Script (remise) | Livraison gratuite ou réduite selon des règles de panier | Cart & Checkout Discounts API |
|
Shipping Script (masquer / renommer / réordonner) | Masquer un tarif au-dessus de X $, renommer "Standard" en "Gratuit dès 50 $" | Delivery Customization API |
|
Payment Script | Masquer PayPal pour le B2B, masquer le paiement à la livraison au-dessus de 500 $, réordonner les modes de paiement | Payment Customization API |
|
Script de modification de panier (rare) | Créer des lots de produits, remplacer des articles | Cart Transform API |
|
Script de blocage du checkout | Refuser le panier si la combinaison de SKU est non valide | Cart & Checkout Validation API |
|
Si vous avez dix Scripts, vous développerez probablement entre trois et cinq Functions — plusieurs Scripts se résument souvent à une seule Function dotée d'une logique de branchement plus propre.

Prérequis : Configurer votre environnement de développement local
Avant de générer une Function, vous devez installer trois outils en local. Exécutez ces vérifications dans votre terminal.
1. Node.js 18+
node --version # Doit être >= 18.0.0
Si la version est plus ancienne, installez-la via nvm ou téléchargez-la sur nodejs.org.
2. Shopify CLI 3+
npm install -g @shopify/cli@latest shopify version # Doit afficher 3.x ou plus
3. Toolchain 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 en JavaScript n'ont pas besoin de Rust. Choisissez un langage pour votre équipe et tenez-vous-y — mélanger les deux ajoute des coûts 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 y déploierez vos Functions avant de les passer en production.
Générer votre première Function
La CLI s'occupe de l'essentiel du code de base. Dans n'importe quel répertoire :
# Créer une nouvelle application Shopify (ignorez si vous en avez déjà une) shopify app init my-checkout-functions cd my-checkout-functions # Générer une extension de type Function shopify app generate extension
La CLI vous guide à travers différentes questions. Pour une Function de réduction, vous choisiriez :
Type : Function
Modèle :
discount(oucart_checkout_validation,delivery_customization,payment_customization, etc.)Langage : Rust ou JavaScript
Nom : par exemple
volume-discount-fn
Cela crée le répertoire extensions/volume-discount-fn/ contenant :
extensions/volume-discount-fn/ ├── shopify.extension.toml # Config 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 en permanence sont le .toml (config), 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 appliquait une remise de 10 % sur le sous-total de la commande dès que le panier contenait au moins 5 articles d'une collection spécifique. Voici l'équivalent sous forme de 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 demandez. Limitez le GraphQL au strict minimum — chaque champ ignoré garantit 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> { // Arrêter 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![] }); } // Sommer les quantités d'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 réduction 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 # Lorsque vous êtes 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 active, versionnée et remplace définitivement l'ancien Script.
Tutoriel 2 : Remplacer un Shipping Script (Masquer un mode de livraison selon le montant du panier)
Un Script classique : « Masquer la livraison Express lorsque le sous-total du panier dépasse 500 $ pour éviter des frais d'envoi de nuit exorbitants sur de grosses commandes. » Voici la version Delivery Customization avec une Function.
Étape 2.1 : Générer l'extension
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 : Activer via l'Admin (sans GraphQL)
Les Delivery Customizations disposent d'une interface d'administration intégrée. Après l'exécution de shopify app deploy :
Allez dans Settings → Shipping and delivery
Faites défiler jusqu'à la section Customizations tout en bas
Cliquez sur Add customization → sélectionnez votre Function
Enregistrez
La règle de masquage est active en production. Aucune mutation requise.

Tutoriel 3 : Remplacer un Payment Script (Masquer le paiement à la livraison pour le B2B)
Ancien Script : « Masquer le paiement à la livraison (COD) pour tout client doté du tag 'B2B'. » Voici la version Payment Customization.
Étape 3.1 : Générer l'extension
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 : Activer
Les Payment Customizations ont également une interface d'administration dans Settings → Payments → Customizations. Même processus que pour la livraison — sélectionnez votre Function, enregistrez, terminé.
Puisque vous lisez ceci — Un mot sur le post-achat
Une mise au point rapide puisque vous êtes sur le blog de Revize. Revize gère ce que les Functions ne peuvent pas toucher — une fois la commande passée, les clients veulent ajouter un article, modifier une taille, corriger l'adresse de livraison ou appliquer un code promo oublié. Les Functions interviennent lors du paiement. Revize intervient après. Les Functions déterminent ce qui est autorisé dans le panier ; Revize offre à vos clients et à votre équipe de support la possibilité de modifier la commande a posteriori sans passer par un cycle d'annulation et de recréation. C'est capital pour deux types de boutiques : celles qui ont un volume de commandes tel que l'édition manuelle devient impossible (les opérateurs Plus, par définition, mais aussi les boutiques Advanced à fort trafic), et celles dont l'image de marque repose sur l'expérience client — où un e-mail indiquant « désolé, nous ne pouvons pas modifier cela » détruit la fidélisation.
Si votre plan de migration couvre Scripts → Functions mais que vous n'avez pas encore résolu la gestion des modifications post-achat, vous vous heurterez au prochain obstacle technique d'ici trois semaines. Le guide de gestion des commandes que nous venons de publier détaille l'ensemble de la stratégie post-paiement.
Retour à la migration.
Stratégie de test : La méthode du tag client
Les Functions ne possèdent pas de « mode brouillon » activable dans l'admin. La bonne pratique professionnelle consiste à conditionner la nouvelle Function à la présence d'un tag client, à exécuter l'ancien Script et la nouvelle Function en parallèle, à vérifier qu'ils produisent des résultats identiques pour les utilisateurs taggués, puis à effectuer la bascule complète.
Étape 1 : Tagger vos utilisateurs de test
Dans la section Customers, ajoutez le tag FN-TESTER à deux ou trois comptes internes.
Étape 2 : Conditionner la Function à la présence du tag
// Au début 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 l'exécution à l'ancien Script } // La logique de la nouvelle Function s'exécute uniquement pour les testeurs
Étape 3 : Ajouter hasAnyTag à votre requête d'entrée
cart { buyerIdentity { customer { hasAnyTag(tags: ["FN-TESTER"]) } } }
Étape 4 : Vérifier dans le checkout
Connectez-vous avec un compte taggué, passez une commande de test, validez que la Function se déclenche. Connectez-vous avec un compte non taggué, validez que l'ancien Script s'exécute toujours. Après quelques jours sans anomalie, retirez la vérification du tag pour appliquer la Function à tous.
Étape 5 : Retirer l'ancien Script
Allez dans Apps → Script Editor → [Votre Script] → Unpublish. Une fois dépublié, la Function devient l'unique source de vérité.
Un flux de déploiement véritablement structuré
Ne déployez pas indéfiniment depuis la machine d'un développeur. Dès que vous avez migré un ou deux Scripts, configurez un véritable 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 token partenaire depuis votre tableau de bord Partner dans Settings → Tokens. Désormais, chaque fusion vers main déploie vos Functions. Fini les discussions Slack pour savoir qui a déployé la dernière version.
Gestion des versions et retour arrière
La commande 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 retour arrière consistait à retrouver l'ancien code manuellement pour le recoller — c'est le jour et la nuit.

Les erreurs les plus fréquentes commises par les équipes
Après avoir accompagné de nombreux marchands Plus dans cette migration l'an dernier, les cinq mêmes erreurs reviennent systématiquement.
1. Traiter les Functions comme un simple portage de Script individuel. Ce n'est pas le cas. Une seule Function peut remplacer trois Scripts grâce à une logique de branchement plus saine. Analysez vos Scripts de manière globale avant de réécrire le code.
2. Oublier les habilitations d'API (scopes d'accès). Beaucoup de Functions nécessitent read_customers, read_orders ou write_discounts. Ajoutez-les dans shopify.app.toml sous la clé scopes et autorisez à nouveau l'application, sans quoi votre requête d'entrée renverra des données nulles.
3. Lancer les Functions pour tous les clients sans test de parité préalable. Même si votre code vous semble correct, des cas particuliers (paniers vides, cartes-cadeaux, avoirs, brouillons de commandes B2B) feront émerger des anomalies. Un déploiement progressif par tag vous évite des pannes bloquantes en production.
4. Faire l'impasse sur le Customizations Report. C'est la cartographie la plus précise de vos personnalisations actives. Ne vous fiez pas à votre mémoire, fiez-vous au rapport.
5. Hardcoder les identifiants de collections et les tags clients. Utilisez la configuration de Function via les metafields si vous avez besoin de valeurs ajustables par les marchands. La CLI permet de générer des configurations basées sur les metafields — consultez la documentation de Shopify à ce sujet.
Feuille de route de migration pour les 75 prochains jours
Un calendrier réaliste semaine par semaine pour aborder le 30 juin sereinement.
Semaines | Action |
|---|---|
Semaine 1 (cette semaine) | Générez le Customizations Report. Listez chaque Script. Choisissez : Function, application publique ou suppression. |
Semaines 2 et 3 | Configurez l'environnement de dev local. Créez 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 liés aux remises. Ce sont les plus longs à traiter en raison de la richesse de l'API Discounts. Testez minutieusement par tag. |
Semaines 7 et 8 | Migrez les Scripts liés à la livraison. Activez les Delivery Customizations dans l'admin. |
Semaines 9 et 10 | Configurez le pipeline CI. Automatisez les déploiements hors des machines locales des développeurs. |
Semaine 11 (mi-juin) | Validation finale de la parité. Désactivez tous les Scripts. Faites tourner la boutique uniquement avec les Functions pendant deux semaines. |
30 juin | Date de fin d'exécution. Aucune interruption de service car vous avez terminé en avance. |
En commençant cette semaine, vous conservez une marge de sécurité. En commençant en juin, vous n'en aurez pas.

Foire Aux Questions
Dois-je posséder un forfait Shopify Plus pour utiliser les Functions ?
Les Functions personnalisées nécessitent Shopify Plus, mais les Functions issues d'applications publiques fonctionnent sur tous les forfaits. Si vous n'êtes pas sur Plus, deux solutions s'offrent à vous : installer une application publique depuis le Shopify App Store qui intègre la Function requise, ou passer à Plus pour concevoir vos propres Functions personnalisées. La plupart des marchands d'envergure utilisant des Scripts disposent déjà de Plus.
Puis-je écrire des Functions en TypeScript ?
Oui — TypeScript est pleinement pris en charge et la CLI configure le projet pour vous. Lorsque vous lancez shopify app generate extension et optez pour « JavaScript », le projet généré inclut les déclarations de types de import("../generated/api"). Vous pouvez renommer vos fichiers en .ts et ajouter un fichier tsconfig.json. Le build final (WASM) sera identique.
Quelle est la rapidité des Functions par rapport aux Scripts ?
Les Functions s'exécutent généralement en moins de 5 ms — soit beaucoup plus rapidement que les Scripts Ruby. Étant compilées en WebAssembly et exécutées dans un environnement optimisé, un budget d'exécution de 5 ms est imposé par Shopify. Si votre Function le dépasse, l'opération est abandonnée. En pratique, une Function bien conçue requiert 1 à 2 ms.
Une Function peut-elle interroger une API externe ?
Non — les Functions ne peuvent effectuer aucun appel réseau. Ce sont des briques de calcul pur : elles reçoivent des données de panier en entrée et renvoient des opérations en sortie. Si vous devez exploiter des données externes (CRM, stock en temps réel), stockez-les préalablement dans des metafields, ou utilisez un autre mécanisme (App Proxy, webhooks, Cart Transform avec appel back-end).
Quelle est la différence entre Cart Transform et les Discounts ?
Les Discounts appliquent des réductions tarifaires ; Cart Transform modifie le contenu même du panier. Utilisez l'API Discounts pour appliquer un code, une remise de 10 %, la livraison gratuite ou du type X achetés Y offerts. Utilisez Cart Transform pour regrouper deux produits sous une ligne unique, ou décomposer une variante en plusieurs éléments. Séparez bien ces deux fonctions lors de votre migration.
Comment tester une Function en local 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 exige une boutique de dev. La CLI propose la commande shopify app function run pour exécuter votre Function face à un fichier d'entrée simulé. Pour valider l'expérience dans le checkout réel, une boutique est incontournable.
Puis-je avoir plusieurs Functions du même type actives simultanément ?
Oui — Shopify autorise plusieurs Functions par cible, exécutées selon un ordre déterminé. Pour les remises, la priorité dépend des règles de cumul de Shopify. Pour les personnalisations de livraison et de paiement, les outputs s'enchaînent. Utiliser une seule Function par cible simplifie grandement la maintenance.
Qu'advient-il de mon Script une fois la Function déployée ?
Les deux s'exécutent en parallèle jusqu'à ce que vous archiviez le Script dans Apps → Script Editor. Ce fonctionnement est voulu pour vous permettre de réaliser des phases de tests parallèles en production. Une fois les tests concluants, désactivez le Script. Au-delà du 30 juin 2026, de toute façon, aucun Script ne fonctionnera plus.
Cette migration aura-t-elle un impact sur mon SEO ou mon thème ?
Non — les Functions s'exécutent côté serveur lors du passage en caisse et n'interfèrent jamais avec votre thème ou vos pages produits. Elles ciblent uniquement les réductions, les choix de livraison et les paiements à l'étape finale. Votre site d'e-commerce et votre référencement ne subissent aucun changement.
Comment migrer un Script qui exploite Input.line_items avec des propriétés personnalisées ?
Ces propriétés personnalisées sont accessibles via le champ attribute des lignes de panier de la requête GraphQL. Ajoutez attribute(key: "votre-clef") { value } au sein de la sélection de lignes. La Function lira cette valeur de la même manière que vos Scripts Ruby lisaient les attributs d'articles.
Qu'en est-il des données analytiques et des tags de commande ? Les Functions peuvent-elles en écrire ?
Les Functions ne peuvent pas appliquer de tags aux commandes ni déclencher de webhooks — elles gèrent exclusivement le panier actif. Pour du taggage ou d'autres flux en aval, utilisez Shopify Flow déclenché par l'événement de création de commande. Associez par exemple une Function pour appliquer la remise et un workflow Flow pour tagguer la commande finale.
Existe-t-il une application publique prête à l'emploi si je ne souhaite pas développer de Function personnalisée ?
Oui — le Shopify App Store propose des dizaines d'applications qui encapsulent les Functions pour les cas d'usage récurrents. Cherchez des termes comme "discount function" ou "payment customization". Pour des stratégies classiques (remise sur quantité, masquer des paiements par tag, livraison gratuite dès X $), cela peut vous éviter plusieurs jours de développement. Réservez le sur-mesure aux règles métiers uniques.
Que se passe-t-il si je dépasse la date limite du 30 juin ?
Le Script s'arrête net — aucun délai de grâce, aucune prolongation ne sera accordée. Tout mécanisme géré par le Script (réduction, frais de port modifiés, mode de paiement masqué) reprendra son comportement par défaut le 1er juillet à minuit UTC. Prévoyez une mise en ligne finale bien avant cette date.
Puis-je supprimer définitivement l'application Script Editor ?
Vous pourrez la désinstaller après le 30 juin 2026, sachant que Shopify devrait la retirer automatiquement. Une fois l'échéance passée, cet éditeur n'aura plus d'utilité. Si votre migration est validée en amont, vous pouvez la supprimer dès maintenant ; vos Functions s'exécutent de manière autonome.
Actions prioritaires pour cette semaine
Ne remettez pas à plus tard. Initiez la transition en accomplissant ces quatre tâches d'ici sept jours.
1. Exportez le Customizations Report. Rendez-vous sur Settings → Checkout → Customizations Report et téléchargez-le. Ce document constitue votre cahier des charges de migration.
2. Installez votre environnement de développement. Mettez en place Node 18+, la CLI Shopify et Rust (si requis). Vérifiez le bon fonctionnement de shopify version. Durée estimée : 30 minutes.
3. Déployez une micro-Function sur une boutique de développement. Sélectionnez le Script le moins complexe (par exemple, le masquage d'une option de paiement). Réalisez sa migration de bout en bout pour éprouver votre pipeline d'outils, même si elle n'est pas déployée immédiatement.
4. Planifiez des plages de travail dans les huit prochaines semaines. Une migration réussie demande du temps dédié. Réservez des créneaux de travail récurrents (par exemple deux après-midis par semaine) et traitez ces phases comme des jalons de livraison majeurs.
Les retours d'expérience montrent souvent le même schéma : deux semaines de latence, trois semaines de développement et une semaine d'ajustements. Cela représente un total de six semaines. Il vous en reste dix. Profitez de cette avance pour soigner vos revues de code et vos étapes de recette.
Une fois votre logique de paiement convertie, l'étape suivante pour la majorité des équipes consiste à optimiser les processus post-achat (corrections d'adresses, ajouts de remises après commande). Si vous intégrez cela à votre feuille de route, sachez que l'application Revize est disponible sur le Shopify App Store et opère aux côtés des nouvelles Functions que vous concevez.
Ressources
Articles connexes
Nous sommes le 16 avril 2026. Hier — le 15 avril — Shopify a définitivement verrouillé le Script Editor. Vous ne pouvez plus créer ni publier de nouveau Script. L'arrêt de l'exécution intervient dans 75 jours, le 30 juin 2026.
Si vous êtes un développeur Shopify Plus — ou l'agence qui gère une boutique Plus — et que vous avez repoussé cette migration au « prochain sprint » ces douze derniers mois, vous avez un problème. Pas un problème cosmétique. Un problème du type « votre tunnel de paiement plante à minuit le 1er juillet ». La plupart des boutiques Plus ont accumulé entre 5 et 20 Scripts au fil des ans, chacun gérant silencieusement une règle de réduction, un masquage de livraison ou une passerelle de paiement que personne ne se souvient avoir codée.
Ce guide est le manuel technique de migration que nous aurions aimé avoir en janvier. Il traite du code réel, pas seulement de la stratégie. À la fin de votre lecture, vous saurez comment échafauder une Function avec la Shopify CLI, écrire la logique en Rust ou JavaScript pour les réductions, les personnalisations de livraison et de paiement, la tester en toute sécurité sur un sous-ensemble de clients ciblé, et la déployer en production sans perturber votre checkout actuel.
Débarrassons votre boutique des Scripts et installons-y les Functions.

Réponse rapide : Scripts → Functions en 60 secondes
La migration en un paragraphe : Les Shopify Scripts (code Ruby dans le Script Editor, réservés à Plus) sont remplacés par les Shopify Functions (modules WebAssembly écrits en Rust ou JavaScript, disponibles pour tous les forfaits). Vous générez une Function avec
shopify app generate extension, écrivez une requêterun.graphqlqui récupère les données de panier nécessaires, écrivez un fichierrun.rsourun.jsqui renvoie les opérations (réductions, modes de livraison masqués, etc.), puis déployez avecshopify app deployet l'activez via l'Admin ou une mutation GraphQL. Les Functions s'exécutent sous forme de WASM compilé avec une latence inférieure à 5 ms, fonctionnent sur tous les forfaits et constituent l'unique voie de personnalisation prise en charge par Shopify à l'avenir.
Ce qui change réellement le 30 juin
Avant de toucher au code, actons les dates. Il y en a deux, et toutes deux sont cruciales.
Date | Événement | Action requise |
|---|---|---|
15 avril 2026 (passé) | Script Editor en lecture seule. Aucun nouveau Script. Aucune modification 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. Définitivement. | Votre Function de remplacement doit être active 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 elle ne l'est pas — et chaque panier concerné appliquera par défaut les tarifs standards, les frais de livraison de base et l'ensemble des modes de paiement activés. Pas de demi-mesure. Le Script s'exécute ou ne s'exécute pas, et après le 30 juin, il ne s'exécutera plus.
Astuce : Allez dans
Settings → Checkout → Customizations Reportdans votre admin Shopify. Vous y trouverez la liste de chaque Script actif sur votre boutique, son rôle et le type de Function de remplacement recommandé. Commencez par là.
Functions vs Scripts : Ce qui a réellement changé
Critère | Shopify Scripts (obsolète) | Shopify Functions (remplacement) |
|---|---|---|
Langage | Ruby DSL (propre à Shopify) | Rust, JavaScript, TypeScript |
Environnement d'exécution | Ruby sandboxé sur l'infrastructure Shopify | WebAssembly (WASM) — exécution < 5ms |
Forfaits compatibles | Plus uniquement | Tous les forfaits (les apps personnalisées nécessitent Plus ; les apps publiques sont ouvertes) |
Éditeur | Script Editor intégré à l'admin | IDE local + Shopify CLI |
Gestion des versions | Aucune — modifications en direct | Compatible Git — contrôle de version complet |
Tests | Manuels dans le checkout | Développement local avec |
Déploiement | Clic sur "Enregistrer" dans l'admin |
|
Cibles | Articles du panier, expédition, paiements | Discounts, Cart Transform, Validation, Delivery Customization, Payment Customization, Order Routing, Fulfillment Constraints, et plus |
Le changement d'architecture est fondamental. Les Scripts consistaient à « bricoler du Ruby dans une zone de texte ». Les Functions consistent à « écrire une véritable application, la versionner, la tester localement, la déployer via un pipeline CI digne de ce nom ». La courbe d'apprentissage est plus raide. C'est aussi la dernière migration que vous aurez à faire pour la logique de checkout dans un avenir prévisible — les Functions représentent l'engagement à long terme de Shopify, contrairement aux Scripts qui se sont avérés être une solution temporaire.
Associer vos Scripts au bon type de Function
Chaque Script actuel correspond à exactement une API de Function. Voici la table de correspondance à garder sous les yeux.
Ancien type de Script | Rôle | Nouvelle API de Function | Cible (Target) |
|---|---|---|---|
Line Item Script | Appliquer des remises à des produits / clients / conditions de panier spécifiques | Cart & Checkout Discounts API |
|
Shipping Script (remise) | Livraison gratuite ou réduite selon des règles de panier | Cart & Checkout Discounts API |
|
Shipping Script (masquer / renommer / réordonner) | Masquer un tarif au-dessus de X $, renommer "Standard" en "Gratuit dès 50 $" | Delivery Customization API |
|
Payment Script | Masquer PayPal pour le B2B, masquer le paiement à la livraison au-dessus de 500 $, réordonner les modes de paiement | Payment Customization API |
|
Script de modification de panier (rare) | Créer des lots de produits, remplacer des articles | Cart Transform API |
|
Script de blocage du checkout | Refuser le panier si la combinaison de SKU est non valide | Cart & Checkout Validation API |
|
Si vous avez dix Scripts, vous développerez probablement entre trois et cinq Functions — plusieurs Scripts se résument souvent à une seule Function dotée d'une logique de branchement plus propre.

Prérequis : Configurer votre environnement de développement local
Avant de générer une Function, vous devez installer trois outils en local. Exécutez ces vérifications dans votre terminal.
1. Node.js 18+
node --version # Doit être >= 18.0.0
Si la version est plus ancienne, installez-la via nvm ou téléchargez-la sur nodejs.org.
2. Shopify CLI 3+
npm install -g @shopify/cli@latest shopify version # Doit afficher 3.x ou plus
3. Toolchain 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 en JavaScript n'ont pas besoin de Rust. Choisissez un langage pour votre équipe et tenez-vous-y — mélanger les deux ajoute des coûts 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 y déploierez vos Functions avant de les passer en production.
Générer votre première Function
La CLI s'occupe de l'essentiel du code de base. Dans n'importe quel répertoire :
# Créer une nouvelle application Shopify (ignorez si vous en avez déjà une) shopify app init my-checkout-functions cd my-checkout-functions # Générer une extension de type Function shopify app generate extension
La CLI vous guide à travers différentes questions. Pour une Function de réduction, vous choisiriez :
Type : Function
Modèle :
discount(oucart_checkout_validation,delivery_customization,payment_customization, etc.)Langage : Rust ou JavaScript
Nom : par exemple
volume-discount-fn
Cela crée le répertoire extensions/volume-discount-fn/ contenant :
extensions/volume-discount-fn/ ├── shopify.extension.toml # Config 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 en permanence sont le .toml (config), 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 appliquait une remise de 10 % sur le sous-total de la commande dès que le panier contenait au moins 5 articles d'une collection spécifique. Voici l'équivalent sous forme de 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 demandez. Limitez le GraphQL au strict minimum — chaque champ ignoré garantit 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> { // Arrêter 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![] }); } // Sommer les quantités d'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 réduction 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 # Lorsque vous êtes 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 active, versionnée et remplace définitivement l'ancien Script.
Tutoriel 2 : Remplacer un Shipping Script (Masquer un mode de livraison selon le montant du panier)
Un Script classique : « Masquer la livraison Express lorsque le sous-total du panier dépasse 500 $ pour éviter des frais d'envoi de nuit exorbitants sur de grosses commandes. » Voici la version Delivery Customization avec une Function.
Étape 2.1 : Générer l'extension
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 : Activer via l'Admin (sans GraphQL)
Les Delivery Customizations disposent d'une interface d'administration intégrée. Après l'exécution de shopify app deploy :
Allez dans Settings → Shipping and delivery
Faites défiler jusqu'à la section Customizations tout en bas
Cliquez sur Add customization → sélectionnez votre Function
Enregistrez
La règle de masquage est active en production. Aucune mutation requise.

Tutoriel 3 : Remplacer un Payment Script (Masquer le paiement à la livraison pour le B2B)
Ancien Script : « Masquer le paiement à la livraison (COD) pour tout client doté du tag 'B2B'. » Voici la version Payment Customization.
Étape 3.1 : Générer l'extension
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 : Activer
Les Payment Customizations ont également une interface d'administration dans Settings → Payments → Customizations. Même processus que pour la livraison — sélectionnez votre Function, enregistrez, terminé.
Puisque vous lisez ceci — Un mot sur le post-achat
Une mise au point rapide puisque vous êtes sur le blog de Revize. Revize gère ce que les Functions ne peuvent pas toucher — une fois la commande passée, les clients veulent ajouter un article, modifier une taille, corriger l'adresse de livraison ou appliquer un code promo oublié. Les Functions interviennent lors du paiement. Revize intervient après. Les Functions déterminent ce qui est autorisé dans le panier ; Revize offre à vos clients et à votre équipe de support la possibilité de modifier la commande a posteriori sans passer par un cycle d'annulation et de recréation. C'est capital pour deux types de boutiques : celles qui ont un volume de commandes tel que l'édition manuelle devient impossible (les opérateurs Plus, par définition, mais aussi les boutiques Advanced à fort trafic), et celles dont l'image de marque repose sur l'expérience client — où un e-mail indiquant « désolé, nous ne pouvons pas modifier cela » détruit la fidélisation.
Si votre plan de migration couvre Scripts → Functions mais que vous n'avez pas encore résolu la gestion des modifications post-achat, vous vous heurterez au prochain obstacle technique d'ici trois semaines. Le guide de gestion des commandes que nous venons de publier détaille l'ensemble de la stratégie post-paiement.
Retour à la migration.
Stratégie de test : La méthode du tag client
Les Functions ne possèdent pas de « mode brouillon » activable dans l'admin. La bonne pratique professionnelle consiste à conditionner la nouvelle Function à la présence d'un tag client, à exécuter l'ancien Script et la nouvelle Function en parallèle, à vérifier qu'ils produisent des résultats identiques pour les utilisateurs taggués, puis à effectuer la bascule complète.
Étape 1 : Tagger vos utilisateurs de test
Dans la section Customers, ajoutez le tag FN-TESTER à deux ou trois comptes internes.
Étape 2 : Conditionner la Function à la présence du tag
// Au début 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 l'exécution à l'ancien Script } // La logique de la nouvelle Function s'exécute uniquement pour les testeurs
Étape 3 : Ajouter hasAnyTag à votre requête d'entrée
cart { buyerIdentity { customer { hasAnyTag(tags: ["FN-TESTER"]) } } }
Étape 4 : Vérifier dans le checkout
Connectez-vous avec un compte taggué, passez une commande de test, validez que la Function se déclenche. Connectez-vous avec un compte non taggué, validez que l'ancien Script s'exécute toujours. Après quelques jours sans anomalie, retirez la vérification du tag pour appliquer la Function à tous.
Étape 5 : Retirer l'ancien Script
Allez dans Apps → Script Editor → [Votre Script] → Unpublish. Une fois dépublié, la Function devient l'unique source de vérité.
Un flux de déploiement véritablement structuré
Ne déployez pas indéfiniment depuis la machine d'un développeur. Dès que vous avez migré un ou deux Scripts, configurez un véritable 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 token partenaire depuis votre tableau de bord Partner dans Settings → Tokens. Désormais, chaque fusion vers main déploie vos Functions. Fini les discussions Slack pour savoir qui a déployé la dernière version.
Gestion des versions et retour arrière
La commande 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 retour arrière consistait à retrouver l'ancien code manuellement pour le recoller — c'est le jour et la nuit.

Les erreurs les plus fréquentes commises par les équipes
Après avoir accompagné de nombreux marchands Plus dans cette migration l'an dernier, les cinq mêmes erreurs reviennent systématiquement.
1. Traiter les Functions comme un simple portage de Script individuel. Ce n'est pas le cas. Une seule Function peut remplacer trois Scripts grâce à une logique de branchement plus saine. Analysez vos Scripts de manière globale avant de réécrire le code.
2. Oublier les habilitations d'API (scopes d'accès). Beaucoup de Functions nécessitent read_customers, read_orders ou write_discounts. Ajoutez-les dans shopify.app.toml sous la clé scopes et autorisez à nouveau l'application, sans quoi votre requête d'entrée renverra des données nulles.
3. Lancer les Functions pour tous les clients sans test de parité préalable. Même si votre code vous semble correct, des cas particuliers (paniers vides, cartes-cadeaux, avoirs, brouillons de commandes B2B) feront émerger des anomalies. Un déploiement progressif par tag vous évite des pannes bloquantes en production.
4. Faire l'impasse sur le Customizations Report. C'est la cartographie la plus précise de vos personnalisations actives. Ne vous fiez pas à votre mémoire, fiez-vous au rapport.
5. Hardcoder les identifiants de collections et les tags clients. Utilisez la configuration de Function via les metafields si vous avez besoin de valeurs ajustables par les marchands. La CLI permet de générer des configurations basées sur les metafields — consultez la documentation de Shopify à ce sujet.
Feuille de route de migration pour les 75 prochains jours
Un calendrier réaliste semaine par semaine pour aborder le 30 juin sereinement.
Semaines | Action |
|---|---|
Semaine 1 (cette semaine) | Générez le Customizations Report. Listez chaque Script. Choisissez : Function, application publique ou suppression. |
Semaines 2 et 3 | Configurez l'environnement de dev local. Créez 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 liés aux remises. Ce sont les plus longs à traiter en raison de la richesse de l'API Discounts. Testez minutieusement par tag. |
Semaines 7 et 8 | Migrez les Scripts liés à la livraison. Activez les Delivery Customizations dans l'admin. |
Semaines 9 et 10 | Configurez le pipeline CI. Automatisez les déploiements hors des machines locales des développeurs. |
Semaine 11 (mi-juin) | Validation finale de la parité. Désactivez tous les Scripts. Faites tourner la boutique uniquement avec les Functions pendant deux semaines. |
30 juin | Date de fin d'exécution. Aucune interruption de service car vous avez terminé en avance. |
En commençant cette semaine, vous conservez une marge de sécurité. En commençant en juin, vous n'en aurez pas.

Foire Aux Questions
Dois-je posséder un forfait Shopify Plus pour utiliser les Functions ?
Les Functions personnalisées nécessitent Shopify Plus, mais les Functions issues d'applications publiques fonctionnent sur tous les forfaits. Si vous n'êtes pas sur Plus, deux solutions s'offrent à vous : installer une application publique depuis le Shopify App Store qui intègre la Function requise, ou passer à Plus pour concevoir vos propres Functions personnalisées. La plupart des marchands d'envergure utilisant des Scripts disposent déjà de Plus.
Puis-je écrire des Functions en TypeScript ?
Oui — TypeScript est pleinement pris en charge et la CLI configure le projet pour vous. Lorsque vous lancez shopify app generate extension et optez pour « JavaScript », le projet généré inclut les déclarations de types de import("../generated/api"). Vous pouvez renommer vos fichiers en .ts et ajouter un fichier tsconfig.json. Le build final (WASM) sera identique.
Quelle est la rapidité des Functions par rapport aux Scripts ?
Les Functions s'exécutent généralement en moins de 5 ms — soit beaucoup plus rapidement que les Scripts Ruby. Étant compilées en WebAssembly et exécutées dans un environnement optimisé, un budget d'exécution de 5 ms est imposé par Shopify. Si votre Function le dépasse, l'opération est abandonnée. En pratique, une Function bien conçue requiert 1 à 2 ms.
Une Function peut-elle interroger une API externe ?
Non — les Functions ne peuvent effectuer aucun appel réseau. Ce sont des briques de calcul pur : elles reçoivent des données de panier en entrée et renvoient des opérations en sortie. Si vous devez exploiter des données externes (CRM, stock en temps réel), stockez-les préalablement dans des metafields, ou utilisez un autre mécanisme (App Proxy, webhooks, Cart Transform avec appel back-end).
Quelle est la différence entre Cart Transform et les Discounts ?
Les Discounts appliquent des réductions tarifaires ; Cart Transform modifie le contenu même du panier. Utilisez l'API Discounts pour appliquer un code, une remise de 10 %, la livraison gratuite ou du type X achetés Y offerts. Utilisez Cart Transform pour regrouper deux produits sous une ligne unique, ou décomposer une variante en plusieurs éléments. Séparez bien ces deux fonctions lors de votre migration.
Comment tester une Function en local 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 exige une boutique de dev. La CLI propose la commande shopify app function run pour exécuter votre Function face à un fichier d'entrée simulé. Pour valider l'expérience dans le checkout réel, une boutique est incontournable.
Puis-je avoir plusieurs Functions du même type actives simultanément ?
Oui — Shopify autorise plusieurs Functions par cible, exécutées selon un ordre déterminé. Pour les remises, la priorité dépend des règles de cumul de Shopify. Pour les personnalisations de livraison et de paiement, les outputs s'enchaînent. Utiliser une seule Function par cible simplifie grandement la maintenance.
Qu'advient-il de mon Script une fois la Function déployée ?
Les deux s'exécutent en parallèle jusqu'à ce que vous archiviez le Script dans Apps → Script Editor. Ce fonctionnement est voulu pour vous permettre de réaliser des phases de tests parallèles en production. Une fois les tests concluants, désactivez le Script. Au-delà du 30 juin 2026, de toute façon, aucun Script ne fonctionnera plus.
Cette migration aura-t-elle un impact sur mon SEO ou mon thème ?
Non — les Functions s'exécutent côté serveur lors du passage en caisse et n'interfèrent jamais avec votre thème ou vos pages produits. Elles ciblent uniquement les réductions, les choix de livraison et les paiements à l'étape finale. Votre site d'e-commerce et votre référencement ne subissent aucun changement.
Comment migrer un Script qui exploite Input.line_items avec des propriétés personnalisées ?
Ces propriétés personnalisées sont accessibles via le champ attribute des lignes de panier de la requête GraphQL. Ajoutez attribute(key: "votre-clef") { value } au sein de la sélection de lignes. La Function lira cette valeur de la même manière que vos Scripts Ruby lisaient les attributs d'articles.
Qu'en est-il des données analytiques et des tags de commande ? Les Functions peuvent-elles en écrire ?
Les Functions ne peuvent pas appliquer de tags aux commandes ni déclencher de webhooks — elles gèrent exclusivement le panier actif. Pour du taggage ou d'autres flux en aval, utilisez Shopify Flow déclenché par l'événement de création de commande. Associez par exemple une Function pour appliquer la remise et un workflow Flow pour tagguer la commande finale.
Existe-t-il une application publique prête à l'emploi si je ne souhaite pas développer de Function personnalisée ?
Oui — le Shopify App Store propose des dizaines d'applications qui encapsulent les Functions pour les cas d'usage récurrents. Cherchez des termes comme "discount function" ou "payment customization". Pour des stratégies classiques (remise sur quantité, masquer des paiements par tag, livraison gratuite dès X $), cela peut vous éviter plusieurs jours de développement. Réservez le sur-mesure aux règles métiers uniques.
Que se passe-t-il si je dépasse la date limite du 30 juin ?
Le Script s'arrête net — aucun délai de grâce, aucune prolongation ne sera accordée. Tout mécanisme géré par le Script (réduction, frais de port modifiés, mode de paiement masqué) reprendra son comportement par défaut le 1er juillet à minuit UTC. Prévoyez une mise en ligne finale bien avant cette date.
Puis-je supprimer définitivement l'application Script Editor ?
Vous pourrez la désinstaller après le 30 juin 2026, sachant que Shopify devrait la retirer automatiquement. Une fois l'échéance passée, cet éditeur n'aura plus d'utilité. Si votre migration est validée en amont, vous pouvez la supprimer dès maintenant ; vos Functions s'exécutent de manière autonome.
Actions prioritaires pour cette semaine
Ne remettez pas à plus tard. Initiez la transition en accomplissant ces quatre tâches d'ici sept jours.
1. Exportez le Customizations Report. Rendez-vous sur Settings → Checkout → Customizations Report et téléchargez-le. Ce document constitue votre cahier des charges de migration.
2. Installez votre environnement de développement. Mettez en place Node 18+, la CLI Shopify et Rust (si requis). Vérifiez le bon fonctionnement de shopify version. Durée estimée : 30 minutes.
3. Déployez une micro-Function sur une boutique de développement. Sélectionnez le Script le moins complexe (par exemple, le masquage d'une option de paiement). Réalisez sa migration de bout en bout pour éprouver votre pipeline d'outils, même si elle n'est pas déployée immédiatement.
4. Planifiez des plages de travail dans les huit prochaines semaines. Une migration réussie demande du temps dédié. Réservez des créneaux de travail récurrents (par exemple deux après-midis par semaine) et traitez ces phases comme des jalons de livraison majeurs.
Les retours d'expérience montrent souvent le même schéma : deux semaines de latence, trois semaines de développement et une semaine d'ajustements. Cela représente un total de six semaines. Il vous en reste dix. Profitez de cette avance pour soigner vos revues de code et vos étapes de recette.
Une fois votre logique de paiement convertie, l'étape suivante pour la majorité des équipes consiste à optimiser les processus post-achat (corrections d'adresses, ajouts de remises après commande). Si vous intégrez cela à votre feuille de route, sachez que l'application Revize est disponible sur le Shopify App Store et opère aux côtés des nouvelles Functions que vous concevez.
Ressources
Articles connexes
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



