Scripts Deadline: Migrer vers Functions d'ici le 30 juin 2026
Scripts Deadline: Migrer vers Functions d'ici le 30 juin 2026
Scripts Deadline: Migrer vers Functions d'ici le 30 juin 2026

Nous sommes le 16 avril 2026. Hier, le 15 avril, Shopify a verrouillé définitivement le Script Editor. Vous ne pouvez plus créer ni publier de nouveau Script. Cette échéance est particulièrement critique pour la logique post-achat : les modifications d'adresse de livraison représentent la modification post-achat numéro 1, comptant pour 30.2 % de toutes les commandes modifiées (Revize, 2026), et tout Script gérant encore ces modifications est désormais figé. L'arrêt complet de l'exécution intervient dans 75 jours, le 30 juin 2026.
Si vous êtes un développeur Shopify Plus — ou l'agence gérant 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 secondaire. Un problème du type « votre passage à la caisse plante à minuit le 1er juillet ». La plupart des boutiques Plus ont accumulé entre 5 et 20 Scripts au fil des ans, chacun gérant discrètement une règle de remise, un masquage de livraison ou une passerelle de paiement que personne ne se rappelle avoir codé.
Ce guide est le manuel de migration technique 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 structurer une Function avec la Shopify CLI, écrire la logique en Rust ou JavaScript pour les remises, les personnalisations de livraison et de paiement, la tester en toute sécurité sur un sous-ensemble ciblé de vos clients, et la déployer en production sans perturber votre processus d'achat actuel.
Retirons les Scripts de votre boutique et installons 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 (remises, 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 la seule méthode de personnalisation prise en charge par Shopify à l'avenir.
Ce qui change réellement le 30 juin
Avant de toucher au code, clarifions les dates. Il y en a deux, et les deux sont cruciales.
Date | Ce qui se passe | Votre action |
|---|---|---|
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 passage à la caisse continue de fonctionner, soit elle ne l'est pas — et chaque panier concerné revient silencieusement aux tarifs standards, aux modes de livraison par défaut et à l'activation de toutes les méthodes de paiement. 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écute plus.
Conseil : Allez dans
Settings → Checkout → Customizations Reportdans votre admin Shopify. Vous y trouverez la liste de tous les Scripts actifs sur votre boutique, leur rôle et le type de Function de remplacement recommandé. Commencez par là.
Functions vs Scripts : Ce qui a changé
Dimension | Shopify Scripts (obsolète) | Shopify Functions (remplacement) |
|---|---|---|
Langage | Ruby DSL (spécifique à Shopify) | Rust, JavaScript, TypeScript |
Runtime | Ruby sandboxé sur l'infra Shopify | WebAssembly (WASM) — exécution < 5 ms |
Disponibilité forfait | Plus uniquement | Tous les forfaits (les applications personnalisées nécessitent Plus ; les applications publiques sont ouvertes) |
Éditeur | Script Editor dans l'admin | IDE local + Shopify CLI |
Contrôle de version | Aucun — modifications en direct | Compatible Git — contrôle de version complet |
Tests | Manuels dans le processus d'achat | Développement local avec |
Déploiement | Clic sur « Enregistrer » dans l'admin |
|
Cibles | Articles, livraison, paiements | Remises, Cart Transform, Validation, Delivery Customization, Payment Customization, Order Routing, Fulfillment Constraints, et plus |
Le changement d'architecture est majeur. Les Scripts consistaient à « modifier du Ruby dans une zone de texte ». Les Functions consistent à « écrire une véritable application, la soumettre au contrôle de version, la tester localement, la déployer via un vrai pipeline CI ». La courbe d'apprentissage est plus raide. C'est aussi la dernière migration de logique de paiement que vous ferez à moyen terme — les Functions représentent l'engagement à long terme de Shopify, pas une solution temporaire comme l'ont été les Scripts.
Associer vos Scripts au bon type de Function
Chaque Script actuel correspond à une API de Function spécifique. Voici le tableau de correspondance à garder sous les yeux.
Ancien type de Script | Rôle | Nouvelle API de Function | Cible de la Function |
|---|---|---|---|
Line Item Script | Appliquer des remises à des produits / clients / conditions de panier spécifiques | Cart & Checkout Discounts API |
|
Shipping Script (remise) | Livraison gratuite / remisée selon les règles du panier | Cart & Checkout Discounts API |
|
Shipping Script (masquer / renommer / réordonner) | Masquer un tarif de livraison 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 méthodes | Payment Customization API |
|
Script modifiant le panier (rare) | Regrouper des produits, remplacer des articles | Cart Transform API |
|
Script de blocage de commande | Rejeter le panier si le mélange de SKU est invalide | Cart & Checkout Validation API |
|
Si vous avez dix Scripts, vous développerez probablement trois à cinq Functions — plusieurs Scripts se regroupent souvent en une seule Function dotée d'une logique d'embranchement plus propre.

Prérequis : Configurer votre environnement de développement local
Avant de générer une Function, vous devez installer trois outils localement. 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 depuis 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 des 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 augmente la charge 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éploirez les Functions avant de les passer en production.
Générer votre première Function
La CLI génère la majeure partie du code de base. Dans n'importe quel répertoire :
# Créer une nouvelle application Shopify (ignorer 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 (ignorer 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 les étapes. Pour une Function de remise, vous choisirez :
Type: Function
Template:
discount(oucart_checkout_validation,delivery_customization,payment_customization, etc.)Language: Rust ou JavaScript
Name: quelque chose comme
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 constamment 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 offrait 10 % de réduction 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 avec une 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 } }
Conseil : Les Functions ne voient que les données que vous demandez. Gardez le GraphQL minimal — chaque champ omis permet 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> { // Sortie 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![] }); } // Somme des 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> { // Sortie 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![] }); } // Somme des 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 # Une fois prêt, déployez shopify app deploy # Dans le panneau GraphiQL qui s'ouvre (appuyez sur `g` dans le terminal de dev), # créez la remise automatique qui utilise votre Function :
# Développement local avec rechargement à chaud shopify app dev # Une fois prêt, déployez shopify app deploy # Dans le panneau GraphiQL qui s'ouvre (appuyez sur `g` dans le terminal de dev), # créez la remise automatique qui utilise votre Function :
mutation { discountAutomaticAppCreate( automaticAppDiscount: { title: "Volume Discount (5+ collection items)" functionHandle: "volume-discount-fn" discountClasses: [ORDER] startsAt: "2026-04-16T00:00:00Z" } ) { automaticAppDiscount { discountId } userErrors { field message } } }
mutation { discountAutomaticAppCreate( automaticAppDiscount: { title: "Volume Discount (5+ collection items)" functionHandle: "volume-discount-fn" discountClasses: [ORDER] startsAt: "2026-04-16T00:00:00Z" } ) { automaticAppDiscount { discountId } userErrors { field message } } }
C'est tout. La Function est active, soumise au contrôle de version et remplace complètement l'ancien Script.
Tutoriel 2 : Remplacer un Shipping Script (Masquer une méthode au-dessus d'un seuil de panier)
Un Script classique : « Masquer la livraison Express lorsque le sous-total du panier dépasse 500 $ pour éviter des envois urgents coûteux sur de grosses commandes ». Voici la version Function de type Delivery Customization.
Étape 2.1 : Génération du code
shopify app generate extension --template delivery_customization --name hide-express-fn
shopify app generate extension --template delivery_customization --name hide-express-fn
Étape 2.2 : Requête d'entrée (src/run.graphql)
query Input { cart { cost { subtotalAmount { amount } } deliveryGroups { deliveryOptions { handle title } } } }
query Input { cart { cost { subtotalAmount { amount } } deliveryGroups { deliveryOptions { handle title } } } }
Étape 2.3 : Logique (src/run.js — variante JavaScript)
// @ts-check /** * @typedef {import("../generated/api").RunInput} RunInput * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult */ const NO_CHANGES = { operations: [] }; const THRESHOLD = 500.0; const HIDE_TITLES = ["Express", "Overnight"]; /** * @param {RunInput} input * @returns {FunctionRunResult} */ export function run(input) { const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount); if (subtotal < THRESHOLD) return NO_CHANGES; const operations = input.cart.deliveryGroups.flatMap((group) => group.deliveryOptions .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t))) .map((opt) => ({ hide: { deliveryOptionHandle: opt.handle }, })) ); return { operations }; }
// @ts-check /** * @typedef {import("../generated/api").RunInput} RunInput * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult */ const NO_CHANGES = { operations: [] }; const THRESHOLD = 500.0; const HIDE_TITLES = ["Express", "Overnight"]; /** * @param {RunInput} input * @returns {FunctionRunResult} */ export function run(input) { const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount); if (subtotal < THRESHOLD) return NO_CHANGES; const operations = input.cart.deliveryGroups.flatMap((group) => group.deliveryOptions .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t))) .map((opt) => ({ hide: { deliveryOptionHandle: opt.handle }, })) ); return { operations }; }
Étape 2.4 : Activation via l'Admin (aucune mutation GraphQL requise)
Les Delivery Customizations disposent d'une interface d'administration intégrée. Après shopify app deploy :
Allez dans Settings → Shipping and delivery
Faites défiler jusqu'à la section Customizations 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 pour tout client ayant le tag 'B2B' ». Voici la version Payment Customization.
Étape 3.1 : Génération du code
shopify app generate extension --template payment_customization --name hide-cod-b2b-fn
shopify app generate extension --template payment_customization --name hide-cod-b2b-fn
Étape 3.2 : Requête d'entrée
query Input { cart { buyerIdentity { customer { hasTags(tags: [{ tag: "B2B" }]) { tag hasTag } } } } paymentMethods { id name } }
query Input { cart { buyerIdentity { customer { hasTags(tags: [{ tag: "B2B" }]) { tag hasTag } } } } paymentMethods { id name } }
Étape 3.3 : Logique (src/run.js)
const NO_CHANGES = { operations: [] }; export function run(input) { const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0]; const isB2B = tagCheck?.hasTag === true; if (!isB2B) return NO_CHANGES; const codMethod = input.paymentMethods.find((pm) => pm.name.toLowerCase().includes("cash on delivery") ); if (!codMethod) return NO_CHANGES; return { operations: [{ hide: { paymentMethodId: codMethod.id } }], }; }
const NO_CHANGES = { operations: [] }; export function run(input) { const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0]; const isB2B = tagCheck?.hasTag === true; if (!isB2B) return NO_CHANGES; const codMethod = input.paymentMethods.find((pm) => pm.name.toLowerCase().includes("cash on delivery") ); if (!codMethod) return NO_CHANGES; return { operations: [{ hide: { paymentMethodId: codMethod.id } }], }; }
Étape 3.4 : Activation
Les Payment Customizations disposent également d'une interface d'administration sous 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 brève mise au point 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, changer de taille, corriger l'adresse de livraison ou appliquer une remise oubliée. Les Functions interviennent lors du passage à la caisse. Revize intervient après. Les Functions déterminent ce qui est autorisé dans le panier ; Revize permet à vos clients et à votre équipe support de modifier la commande après coup sans passer par un cycle d'annulation et de réédition. Cela compte pour deux types de boutiques : celles avec un volume de commandes tel que la modification manuelle devient impossible (les boutiques Plus, évidemment, 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 » nuit à la fidélisation.
Si votre plan de migration prévoit de passer des Scripts aux Functions mais que vous n'avez pas encore résolu la modification des commandes post-achat, vous vous heurterez rapidement à un autre obstacle. Le guide de gestion des commandes que nous venons de publier présente l'ensemble des bonnes pratiques post-achat.
Revenons à la migration.
Stratégie de test : La méthode des clients taggués
Les Functions n'ont pas de « mode brouillon » activable dans l'admin. La méthode professionnelle consiste à conditionner la nouvelle Function à un tag client, à exécuter l'ancien Script et la nouvelle Function en parallèle, à vérifier qu'ils produisent un résultat identique pour les utilisateurs taggués, puis à basculer définitivement.
Étape 1 : Taguez vos utilisateurs de test
Dans 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); // Passage à l'ancien Script existant } // La logique de la nouvelle Function s'exécute uniquement pour les utilisateurs taggués
// 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); // Passage à l'ancien Script existant } // La logique de la nouvelle Function s'exécute uniquement pour les utilisateurs taggués
Étape 3 : Ajoutez hasAnyTag à votre requête d'entrée
cart { buyerIdentity { customer { hasAnyTag(tags: ["FN-TESTER"]) } } }
cart { buyerIdentity { customer { hasAnyTag(tags: ["FN-TESTER"]) } } }
Étape 4 : Vérifier dans le processus d'achat
Connectez-vous avec un compte taggué, passez commande, confirmez que la Function s'active. Connectez-vous avec un compte non taggué, confirmez que l'ancien Script s'exécute toujours. Une fois la parité validée sur quelques jours, retirez la vérification du tag pour appliquer la Function à tous.
Étape 5 : Désactiver l'ancien Script
Allez dans Apps → Script Editor → [Votre Script] → Unpublish. Une fois désactivé, la Function devient la seule source de vérité.
Workflow de déploiement évolutif
Ne déployez pas indéfiniment depuis l'ordinateur d'un développeur. Une fois un ou deux Scripts migrés, 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 jeton de partenaire depuis votre tableau de bord Partner sous Settings → Tokens. Désormais, chaque fusion sur main déploie vos Functions. Fini les discussions sur Slack pour savoir qui a déployé la dernière version.
Gestion des versions et retour arrière
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
Par rapport aux Scripts — où le retour arrière nécessitait de retrouver l'ancien code pour le recoller — la différence est radicale.

Ce que la plupart des équipes ratent
Après avoir accompagné des marchands Plus dans cette migration l'année passée, les cinq mêmes erreurs reviennent systématiquement.
1. Traiter les Functions comme une simple copie conforme des Scripts. Ce n'est pas le cas. Une seule Function peut remplacer trois Scripts grâce à une logique d'embranchement plus propre. Analysez vos Scripts de manière globale avant de réécrire.
2. Oublier les scopes de lecture. De nombreuses Functions requièrent read_customers, read_orders ou write_discounts. Ajoutez-les dans shopify.app.toml sous scopes et ré-autorisez l'application, sinon votre requête d'entrée renverra null.
3. Lancer les Functions sur des clients non taggués sans test de parité. Même si votre code semble correct, des cas limites (panier vide, cartes-cadeaux, avoirs de boutique, brouillons B2B) révéleront des failles. Un déploiement progressif avec tag vous prend deux jours de plus mais vous évite une panne critique.
4. Ignorer le Customizations Report. C'est le meilleur inventaire de ce qui s'exécute réellement sur votre boutique. Ne migrez pas de mémoire — basez-vous sur ce rapport.
5. Hardcoder les IDs de collection et les tags clients. Utilisez la configuration de Function via les metafields si vous avez besoin de valeurs ajustables par le marchand. La CLI peut générer des configurations basées sur les metafields — consultez la documentation de Shopify à ce sujet.
Plan d'action pour les 75 prochains jours
Un planning réaliste pour aborder sereinement l'échéance du 30 juin.
Semaine | Action |
|---|---|
Semaine 1 (cette semaine) | Consulter le Customizations Report. Inventorier chaque Script. Décider entre Function, application publique ou suppression. |
Semaines 2–3 | Configurer l'environnement de développement local. Générer la première Function. Migrer le Script le plus simple (généralement une règle de masquage de paiement). |
Semaines 4–6 | Migrer les Scripts de remise. Ce sont ceux qui prennent le plus de temps car la Discounts API est la plus complète. Réaliser des tests approfondis par tag. |
Semaines 7–8 | Migrer les Scripts de livraison. Activer les Delivery Customizations via l'Admin. |
Semaines 9–10 | Configurer le pipeline CI. Automatiser tous les déploiements. |
Semaine 11 (mi-juin) | Vérification finale de parité. Désactiver tous les Scripts. Faire tourner la boutique uniquement avec les Functions pendant deux semaines. |
30 juin | Date butoir. Tout fonctionne car vous avez terminé en avance. |
Si vous commencez cette semaine, vous conservez une marge de sécurité. Si vous commencez en juin, vous n'en aurez pas.

Foire Aux Questions
Ai-je besoin de 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 choix s'offrent à vous : installer une application publique depuis le Shopify App Store qui déploie la Function pour vous, ou passer à Plus pour coder vos propres Functions personnalisées. La plupart des grands marchands utilisant des Scripts possédaient déjà Plus, ce qui ne change presque rien en pratique.
Puis-je écrire des Functions en TypeScript?
Oui — TypeScript est entièrement pris en charge et la CLI le configure pour vous. Lorsque vous lancez shopify app generate extension et choisissez « JavaScript », le projet généré inclut les déclarations de types de import("../generated/api"). Vous pouvez renommer les fichiers en .ts et ajouter un tsconfig.json si vous préférez. Le fichier compilé final (WASM) est strictement identique quel que soit le langage source.
Quelle est la rapidité des Functions par rapport aux Scripts?
Les Functions s'exécutent généralement en moins de 5 ms — soit nettement plus vite que les Scripts Ruby. Comme elles sont compilées en WebAssembly et s'exécutent dans un environnement restreint, Shopify impose une limite d'exécution de 5 ms. Si votre Function la dépasse, l'opération est abandonnée et la Function ne renvoie rien. En pratique, une Function bien conçue nécessite 1 à 2 ms. Les performances sont bien supérieures à celles des Scripts.
Une Function peut-elle appeler une API externe?
Non — les Functions ne peuvent pas effectuer de requêtes réseau. Il s'agit uniquement de calcul pur : données du panier en entrée → opérations en sortie. Si vous avez besoin de données externes (recherche CRM, vérification d'inventaire en temps réel), vous devez soit stocker ces données dans des metafields au préalable, soit utiliser une autre méthode (App Proxy, webhooks, Cart Transform avec appel back-end). C'est la raison la plus fréquente pour laquelle les équipes doivent repenser l'architecture plutôt que de faire un simple portage.
Quelle est la différence entre Cart Transform et les remises?
Les remises modifient les prix, tandis que Cart Transform modifie le contenu du panier. Utilisez la Discounts API pour appliquer un rabais de 10 %, offrir la livraison ou proposer une offre de type BOGO. Utilisez Cart Transform pour regrouper deux produits en un seul article, ou diviser une variante en plusieurs. De nombreux anciens Scripts mélangeaient ces deux aspects — lors de la migration, séparez-les en deux Functions distinctes.
Comment tester une Function localement sans boutique de développement?
Vous pouvez exécuter des tests unitaires avec cargo test (Rust) ou npm test (JS), mais les tests d'intégration complets requièrent une boutique de développement. La CLI propose shopify app function run qui exécute votre Function avec un fichier d'entrée de test — idéal pour itérer rapidement. Mais pour valider le comportement final du passage à la caisse de bout en bout, vous avez besoin d'une véritable boutique avec un panier réel.
Puis-je avoir plusieurs Functions du même type?
Oui — Shopify prend en charge plusieurs Functions par cible, et elles s'exécutent dans un ordre déterminé. Pour les remises, l'ordre est régi par les règles de cumul de Shopify. Pour les Delivery et Payment Customizations, vous pouvez chaîner les Functions, la sortie de l'une alimentant l'entrée de la suivante. La plupart des équipes utilisent une seule Function par type pour simplifier la gestion.
Qu'advient-il de mon Script après le déploiement de la Function?
Les deux s'exécutent en parallèle jusqu'à ce que vous désactiviez le Script dans Apps → Script Editor. Cela est intentionnel et vous permet de réaliser vos tests en conditions réelles. Après validation de la Function, désactivez manuellement le Script. Après le 30 juin 2026, tous les Scripts cesseront de s'exécuter, qu'ils soient désactivés ou non.
La 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 à la caisse et n'interfèrent jamais avec votre thème ou vos pages produits. Elles modifient uniquement les remises, les options de livraison et les méthodes de paiement lors du paiement. Votre boutique en ligne, vos fiches produits et votre SEO restent inchangés.
Comment migrer un Script qui utilise Input.line_items avec des propriétés personnalisées?
Les propriétés personnalisées sont accessibles via le champ attribute des lignes du panier dans l'entrée GraphQL. Ajoutez attribute(key: "votre-cle") { value } dans la sélection lines. La Function les lit de la même manière que les Scripts lisaient les propriétés d'articles, mais via GraphQL plutôt que par des appels de méthodes Ruby.
Qu'en est-il des analyses de données et des tags de commande? Les Functions peuvent-elles écrire des données?
Les Functions ne peuvent pas écrire de tags de commande ni déclencher de webhooks — elles renvoient uniquement des opérations sur le panier en cours. Pour le taggage ou les flux de travail en aval, utilisez Shopify Flow déclenché par l'événement de création de commande. De nombreux marchands associent une Function (pour la remise) à un Flow (pour ajouter le tag « VOLUME-DISCOUNT-APPLIED » sur la commande).
Existe-t-il une application publique que je peux installer au lieu de développer une Function personnalisée?
Oui — le Shopify App Store propose des dizaines d'applications qui intègrent des Functions pour les cas d'usage courants. Recherchez « discount function », « delivery customization » ou « payment customization ». Pour des besoins classiques (remises sur volume, masquage de paiement par tag, livraison gratuite dès X $), une application existante peut vous éviter des jours de développement. Réservez les Functions personnalisées aux logiques réellement spécifiques à votre activité.
Que se passe-t-il si je dépasse la date limite du 30 juin?
Le Script s'arrête — il n'y a pas de solution de repli, pas de période de grâce et aucun report possible. Quelle que soit la fonction du Script (remise, masquage de tarif de livraison, blocage de paiement), le comportement par défaut sera rétabli à minuit UTC le 1er juillet. Si votre activité dépend de cette logique, prévoyez d'être opérationnel bien avant cette date. La migration prend généralement plus de temps que prévu, notamment en raison des tests de parité.
Puis-je supprimer définitivement l'application Script Editor?
Vous pourrez la désinstaller après le 30 juin 2026, mais Shopify la retirera probablement d'office. Une fois que les Scripts ne s'exécutent plus, l'éditeur n'a plus d'utilité. Vous pouvez également désactiver tous vos Scripts dès maintenant et désinstaller l'application immédiatement si votre migration est terminée — vos Functions fonctionnent de manière autonome.
Ce qu'il faut faire cette semaine
Ne vous contentez pas de lire cet article. Réalisez ces quatre actions dans les sept prochains jours.
1. Récupérer le Customizations Report. Allez dans Settings → Checkout → Customizations Report. Exportez-le. C'est votre base de travail pour la migration.
2. Configurer votre environnement de dev. Installez Node 18+, la Shopify CLI et Rust (si nécessaire). Vérifiez que shopify version fonctionne. Durée estimée : 30 minutes.
3. Générer et déployer une petite Function sur une boutique de dev. Choisissez le Script le plus simple — souvent une règle de masquage de paiement. Migrez-le de bout en bout. Même s'il ne va pas en production, vous aurez validé votre environnement de travail.
4. Bloquer des créneaux dans votre calendrier pour les huit prochaines semaines. Une migration ne se fait pas à la va-vite entre deux tâches quotidiennes. Réservez des plages régulières — par exemple chaque mardi et jeudi après-midi — et traitez ce projet comme une priorité absolue.
Parmi les équipes que nous avons accompagnées, le schéma reste le même : deux semaines d'attente, trois semaines de développement réel, une semaine de finalisation. Cela représente six semaines. Il vous en reste dix. Profitez de cette marge pour la revue de code et l'assurance qualité, sans repousser le lancement du projet.
Et une fois la logique de paiement opérationnelle, l'étape suivante pour la plupart des marchands est le post-achat — modifications d'adresses, échanges d'articles ou ajouts de remises après commande. Si cela fait partie de vos projets (et cela devrait être le cas, que vous soyez un marchand Plus à fort volume ou une boutique Advanced axée sur l'expérience client), Revize est disponible sur le Shopify App Store et fonctionne en parfaite synergie avec toutes les Functions que vous développerez.
Ressources
Articles connexes
Shopify Checkout Extensibility 2026: You Missed the Deadline. Now What?
The Universal Commerce Protocol (UCP): What Every Shopify Developer Needs to Know
Best Shopify Customer Service Apps for 2025 (Tested & Ranked)
Mis à jour en août 2026. Revize est une application Shopify permettant aux clients de modifier eux-mêmes leurs commandes après l'achat. Elle permet aux acheteurs de modifier leur adresse de livraison, d'échanger une variante ou un produit, d'annuler et d'obtenir un remboursement ou un avoir avant le traitement de la commande, le tout sans ouvrir de ticket d'assistance. En savoir plus sur la possibilité de permettre aux clients de modifier leurs propres commandes Shopify, ou retrouver Revize sur le Shopify App Store.
Nous sommes le 16 avril 2026. Hier, le 15 avril, Shopify a verrouillé définitivement le Script Editor. Vous ne pouvez plus créer ni publier de nouveau Script. Cette échéance est particulièrement critique pour la logique post-achat : les modifications d'adresse de livraison représentent la modification post-achat numéro 1, comptant pour 30.2 % de toutes les commandes modifiées (Revize, 2026), et tout Script gérant encore ces modifications est désormais figé. L'arrêt complet de l'exécution intervient dans 75 jours, le 30 juin 2026.
Si vous êtes un développeur Shopify Plus — ou l'agence gérant 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 secondaire. Un problème du type « votre passage à la caisse plante à minuit le 1er juillet ». La plupart des boutiques Plus ont accumulé entre 5 et 20 Scripts au fil des ans, chacun gérant discrètement une règle de remise, un masquage de livraison ou une passerelle de paiement que personne ne se rappelle avoir codé.
Ce guide est le manuel de migration technique 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 structurer une Function avec la Shopify CLI, écrire la logique en Rust ou JavaScript pour les remises, les personnalisations de livraison et de paiement, la tester en toute sécurité sur un sous-ensemble ciblé de vos clients, et la déployer en production sans perturber votre processus d'achat actuel.
Retirons les Scripts de votre boutique et installons 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 (remises, 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 la seule méthode de personnalisation prise en charge par Shopify à l'avenir.
Ce qui change réellement le 30 juin
Avant de toucher au code, clarifions les dates. Il y en a deux, et les deux sont cruciales.
Date | Ce qui se passe | Votre action |
|---|---|---|
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 passage à la caisse continue de fonctionner, soit elle ne l'est pas — et chaque panier concerné revient silencieusement aux tarifs standards, aux modes de livraison par défaut et à l'activation de toutes les méthodes de paiement. 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écute plus.
Conseil : Allez dans
Settings → Checkout → Customizations Reportdans votre admin Shopify. Vous y trouverez la liste de tous les Scripts actifs sur votre boutique, leur rôle et le type de Function de remplacement recommandé. Commencez par là.
Functions vs Scripts : Ce qui a changé
Dimension | Shopify Scripts (obsolète) | Shopify Functions (remplacement) |
|---|---|---|
Langage | Ruby DSL (spécifique à Shopify) | Rust, JavaScript, TypeScript |
Runtime | Ruby sandboxé sur l'infra Shopify | WebAssembly (WASM) — exécution < 5 ms |
Disponibilité forfait | Plus uniquement | Tous les forfaits (les applications personnalisées nécessitent Plus ; les applications publiques sont ouvertes) |
Éditeur | Script Editor dans l'admin | IDE local + Shopify CLI |
Contrôle de version | Aucun — modifications en direct | Compatible Git — contrôle de version complet |
Tests | Manuels dans le processus d'achat | Développement local avec |
Déploiement | Clic sur « Enregistrer » dans l'admin |
|
Cibles | Articles, livraison, paiements | Remises, Cart Transform, Validation, Delivery Customization, Payment Customization, Order Routing, Fulfillment Constraints, et plus |
Le changement d'architecture est majeur. Les Scripts consistaient à « modifier du Ruby dans une zone de texte ». Les Functions consistent à « écrire une véritable application, la soumettre au contrôle de version, la tester localement, la déployer via un vrai pipeline CI ». La courbe d'apprentissage est plus raide. C'est aussi la dernière migration de logique de paiement que vous ferez à moyen terme — les Functions représentent l'engagement à long terme de Shopify, pas une solution temporaire comme l'ont été les Scripts.
Associer vos Scripts au bon type de Function
Chaque Script actuel correspond à une API de Function spécifique. Voici le tableau de correspondance à garder sous les yeux.
Ancien type de Script | Rôle | Nouvelle API de Function | Cible de la Function |
|---|---|---|---|
Line Item Script | Appliquer des remises à des produits / clients / conditions de panier spécifiques | Cart & Checkout Discounts API |
|
Shipping Script (remise) | Livraison gratuite / remisée selon les règles du panier | Cart & Checkout Discounts API |
|
Shipping Script (masquer / renommer / réordonner) | Masquer un tarif de livraison 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 méthodes | Payment Customization API |
|
Script modifiant le panier (rare) | Regrouper des produits, remplacer des articles | Cart Transform API |
|
Script de blocage de commande | Rejeter le panier si le mélange de SKU est invalide | Cart & Checkout Validation API |
|
Si vous avez dix Scripts, vous développerez probablement trois à cinq Functions — plusieurs Scripts se regroupent souvent en une seule Function dotée d'une logique d'embranchement plus propre.

Prérequis : Configurer votre environnement de développement local
Avant de générer une Function, vous devez installer trois outils localement. 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 depuis 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 des 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 augmente la charge 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éploirez les Functions avant de les passer en production.
Générer votre première Function
La CLI génère la majeure partie du code de base. Dans n'importe quel répertoire :
# Créer une nouvelle application Shopify (ignorer 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 les étapes. Pour une Function de remise, vous choisirez :
Type: Function
Template:
discount(oucart_checkout_validation,delivery_customization,payment_customization, etc.)Language: Rust ou JavaScript
Name: quelque chose comme
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 constamment 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 offrait 10 % de réduction 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 avec une 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 } }
Conseil : Les Functions ne voient que les données que vous demandez. Gardez le GraphQL minimal — chaque champ omis permet 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> { // Sortie 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![] }); } // Somme des 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 # Une fois prêt, déployez shopify app deploy # Dans le panneau GraphiQL qui s'ouvre (appuyez sur `g` dans le terminal de dev), # créez la remise automatique qui utilise votre Function :
mutation { discountAutomaticAppCreate( automaticAppDiscount: { title: "Volume Discount (5+ collection items)" functionHandle: "volume-discount-fn" discountClasses: [ORDER] startsAt: "2026-04-16T00:00:00Z" } ) { automaticAppDiscount { discountId } userErrors { field message } } }
C'est tout. La Function est active, soumise au contrôle de version et remplace complètement l'ancien Script.
Tutoriel 2 : Remplacer un Shipping Script (Masquer une méthode au-dessus d'un seuil de panier)
Un Script classique : « Masquer la livraison Express lorsque le sous-total du panier dépasse 500 $ pour éviter des envois urgents coûteux sur de grosses commandes ». Voici la version Function de type Delivery Customization.
Étape 2.1 : Génération du code
shopify app generate extension --template delivery_customization --name hide-express-fn
Étape 2.2 : Requête d'entrée (src/run.graphql)
query Input { cart { cost { subtotalAmount { amount } } deliveryGroups { deliveryOptions { handle title } } } }
Étape 2.3 : Logique (src/run.js — variante JavaScript)
// @ts-check /** * @typedef {import("../generated/api").RunInput} RunInput * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult */ const NO_CHANGES = { operations: [] }; const THRESHOLD = 500.0; const HIDE_TITLES = ["Express", "Overnight"]; /** * @param {RunInput} input * @returns {FunctionRunResult} */ export function run(input) { const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount); if (subtotal < THRESHOLD) return NO_CHANGES; const operations = input.cart.deliveryGroups.flatMap((group) => group.deliveryOptions .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t))) .map((opt) => ({ hide: { deliveryOptionHandle: opt.handle }, })) ); return { operations }; }
Étape 2.4 : Activation via l'Admin (aucune mutation GraphQL requise)
Les Delivery Customizations disposent d'une interface d'administration intégrée. Après shopify app deploy :
Allez dans Settings → Shipping and delivery
Faites défiler jusqu'à la section Customizations 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 pour tout client ayant le tag 'B2B' ». Voici la version Payment Customization.
Étape 3.1 : Génération du code
shopify app generate extension --template payment_customization --name hide-cod-b2b-fn
Étape 3.2 : Requête d'entrée
query Input { cart { buyerIdentity { customer { hasTags(tags: [{ tag: "B2B" }]) { tag hasTag } } } } paymentMethods { id name } }
Étape 3.3 : Logique (src/run.js)
const NO_CHANGES = { operations: [] }; export function run(input) { const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0]; const isB2B = tagCheck?.hasTag === true; if (!isB2B) return NO_CHANGES; const codMethod = input.paymentMethods.find((pm) => pm.name.toLowerCase().includes("cash on delivery") ); if (!codMethod) return NO_CHANGES; return { operations: [{ hide: { paymentMethodId: codMethod.id } }], }; }
Étape 3.4 : Activation
Les Payment Customizations disposent également d'une interface d'administration sous 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 brève mise au point 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, changer de taille, corriger l'adresse de livraison ou appliquer une remise oubliée. Les Functions interviennent lors du passage à la caisse. Revize intervient après. Les Functions déterminent ce qui est autorisé dans le panier ; Revize permet à vos clients et à votre équipe support de modifier la commande après coup sans passer par un cycle d'annulation et de réédition. Cela compte pour deux types de boutiques : celles avec un volume de commandes tel que la modification manuelle devient impossible (les boutiques Plus, évidemment, 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 » nuit à la fidélisation.
Si votre plan de migration prévoit de passer des Scripts aux Functions mais que vous n'avez pas encore résolu la modification des commandes post-achat, vous vous heurterez rapidement à un autre obstacle. Le guide de gestion des commandes que nous venons de publier présente l'ensemble des bonnes pratiques post-achat.
Revenons à la migration.
Stratégie de test : La méthode des clients taggués
Les Functions n'ont pas de « mode brouillon » activable dans l'admin. La méthode professionnelle consiste à conditionner la nouvelle Function à un tag client, à exécuter l'ancien Script et la nouvelle Function en parallèle, à vérifier qu'ils produisent un résultat identique pour les utilisateurs taggués, puis à basculer définitivement.
Étape 1 : Taguez vos utilisateurs de test
Dans 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); // Passage à l'ancien Script existant } // La logique de la nouvelle Function s'exécute uniquement pour les utilisateurs taggués
Étape 3 : Ajoutez hasAnyTag à votre requête d'entrée
cart { buyerIdentity { customer { hasAnyTag(tags: ["FN-TESTER"]) } } }
Étape 4 : Vérifier dans le processus d'achat
Connectez-vous avec un compte taggué, passez commande, confirmez que la Function s'active. Connectez-vous avec un compte non taggué, confirmez que l'ancien Script s'exécute toujours. Une fois la parité validée sur quelques jours, retirez la vérification du tag pour appliquer la Function à tous.
Étape 5 : Désactiver l'ancien Script
Allez dans Apps → Script Editor → [Votre Script] → Unpublish. Une fois désactivé, la Function devient la seule source de vérité.
Workflow de déploiement évolutif
Ne déployez pas indéfiniment depuis l'ordinateur d'un développeur. Une fois un ou deux Scripts migrés, 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 jeton de partenaire depuis votre tableau de bord Partner sous Settings → Tokens. Désormais, chaque fusion sur main déploie vos Functions. Fini les discussions sur Slack pour savoir qui a déployé la dernière version.
Gestion des versions et retour arrière
shopify app deploy crée un instantané versionné. Pour revenir en arrière :
shopify app versions list shopify app release --version <previous-version-id
Par rapport aux Scripts — où le retour arrière nécessitait de retrouver l'ancien code pour le recoller — la différence est radicale.

Ce que la plupart des équipes ratent
Après avoir accompagné des marchands Plus dans cette migration l'année passée, les cinq mêmes erreurs reviennent systématiquement.
1. Traiter les Functions comme une simple copie conforme des Scripts. Ce n'est pas le cas. Une seule Function peut remplacer trois Scripts grâce à une logique d'embranchement plus propre. Analysez vos Scripts de manière globale avant de réécrire.
2. Oublier les scopes de lecture. De nombreuses Functions requièrent read_customers, read_orders ou write_discounts. Ajoutez-les dans shopify.app.toml sous scopes et ré-autorisez l'application, sinon votre requête d'entrée renverra null.
3. Lancer les Functions sur des clients non taggués sans test de parité. Même si votre code semble correct, des cas limites (panier vide, cartes-cadeaux, avoirs de boutique, brouillons B2B) révéleront des failles. Un déploiement progressif avec tag vous prend deux jours de plus mais vous évite une panne critique.
4. Ignorer le Customizations Report. C'est le meilleur inventaire de ce qui s'exécute réellement sur votre boutique. Ne migrez pas de mémoire — basez-vous sur ce rapport.
5. Hardcoder les IDs de collection et les tags clients. Utilisez la configuration de Function via les metafields si vous avez besoin de valeurs ajustables par le marchand. La CLI peut générer des configurations basées sur les metafields — consultez la documentation de Shopify à ce sujet.
Plan d'action pour les 75 prochains jours
Un planning réaliste pour aborder sereinement l'échéance du 30 juin.
Semaine | Action |
|---|---|
Semaine 1 (cette semaine) | Consulter le Customizations Report. Inventorier chaque Script. Décider entre Function, application publique ou suppression. |
Semaines 2–3 | Configurer l'environnement de développement local. Générer la première Function. Migrer le Script le plus simple (généralement une règle de masquage de paiement). |
Semaines 4–6 | Migrer les Scripts de remise. Ce sont ceux qui prennent le plus de temps car la Discounts API est la plus complète. Réaliser des tests approfondis par tag. |
Semaines 7–8 | Migrer les Scripts de livraison. Activer les Delivery Customizations via l'Admin. |
Semaines 9–10 | Configurer le pipeline CI. Automatiser tous les déploiements. |
Semaine 11 (mi-juin) | Vérification finale de parité. Désactiver tous les Scripts. Faire tourner la boutique uniquement avec les Functions pendant deux semaines. |
30 juin | Date butoir. Tout fonctionne car vous avez terminé en avance. |
Si vous commencez cette semaine, vous conservez une marge de sécurité. Si vous commencez en juin, vous n'en aurez pas.

Foire Aux Questions
Ai-je besoin de 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 choix s'offrent à vous : installer une application publique depuis le Shopify App Store qui déploie la Function pour vous, ou passer à Plus pour coder vos propres Functions personnalisées. La plupart des grands marchands utilisant des Scripts possédaient déjà Plus, ce qui ne change presque rien en pratique.
Puis-je écrire des Functions en TypeScript?
Oui — TypeScript est entièrement pris en charge et la CLI le configure pour vous. Lorsque vous lancez shopify app generate extension et choisissez « JavaScript », le projet généré inclut les déclarations de types de import("../generated/api"). Vous pouvez renommer les fichiers en .ts et ajouter un tsconfig.json si vous préférez. Le fichier compilé final (WASM) est strictement identique quel que soit le langage source.
Quelle est la rapidité des Functions par rapport aux Scripts?
Les Functions s'exécutent généralement en moins de 5 ms — soit nettement plus vite que les Scripts Ruby. Comme elles sont compilées en WebAssembly et s'exécutent dans un environnement restreint, Shopify impose une limite d'exécution de 5 ms. Si votre Function la dépasse, l'opération est abandonnée et la Function ne renvoie rien. En pratique, une Function bien conçue nécessite 1 à 2 ms. Les performances sont bien supérieures à celles des Scripts.
Une Function peut-elle appeler une API externe?
Non — les Functions ne peuvent pas effectuer de requêtes réseau. Il s'agit uniquement de calcul pur : données du panier en entrée → opérations en sortie. Si vous avez besoin de données externes (recherche CRM, vérification d'inventaire en temps réel), vous devez soit stocker ces données dans des metafields au préalable, soit utiliser une autre méthode (App Proxy, webhooks, Cart Transform avec appel back-end). C'est la raison la plus fréquente pour laquelle les équipes doivent repenser l'architecture plutôt que de faire un simple portage.
Quelle est la différence entre Cart Transform et les remises?
Les remises modifient les prix, tandis que Cart Transform modifie le contenu du panier. Utilisez la Discounts API pour appliquer un rabais de 10 %, offrir la livraison ou proposer une offre de type BOGO. Utilisez Cart Transform pour regrouper deux produits en un seul article, ou diviser une variante en plusieurs. De nombreux anciens Scripts mélangeaient ces deux aspects — lors de la migration, séparez-les en deux Functions distinctes.
Comment tester une Function localement sans boutique de développement?
Vous pouvez exécuter des tests unitaires avec cargo test (Rust) ou npm test (JS), mais les tests d'intégration complets requièrent une boutique de développement. La CLI propose shopify app function run qui exécute votre Function avec un fichier d'entrée de test — idéal pour itérer rapidement. Mais pour valider le comportement final du passage à la caisse de bout en bout, vous avez besoin d'une véritable boutique avec un panier réel.
Puis-je avoir plusieurs Functions du même type?
Oui — Shopify prend en charge plusieurs Functions par cible, et elles s'exécutent dans un ordre déterminé. Pour les remises, l'ordre est régi par les règles de cumul de Shopify. Pour les Delivery et Payment Customizations, vous pouvez chaîner les Functions, la sortie de l'une alimentant l'entrée de la suivante. La plupart des équipes utilisent une seule Function par type pour simplifier la gestion.
Qu'advient-il de mon Script après le déploiement de la Function?
Les deux s'exécutent en parallèle jusqu'à ce que vous désactiviez le Script dans Apps → Script Editor. Cela est intentionnel et vous permet de réaliser vos tests en conditions réelles. Après validation de la Function, désactivez manuellement le Script. Après le 30 juin 2026, tous les Scripts cesseront de s'exécuter, qu'ils soient désactivés ou non.
La 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 à la caisse et n'interfèrent jamais avec votre thème ou vos pages produits. Elles modifient uniquement les remises, les options de livraison et les méthodes de paiement lors du paiement. Votre boutique en ligne, vos fiches produits et votre SEO restent inchangés.
Comment migrer un Script qui utilise Input.line_items avec des propriétés personnalisées?
Les propriétés personnalisées sont accessibles via le champ attribute des lignes du panier dans l'entrée GraphQL. Ajoutez attribute(key: "votre-cle") { value } dans la sélection lines. La Function les lit de la même manière que les Scripts lisaient les propriétés d'articles, mais via GraphQL plutôt que par des appels de méthodes Ruby.
Qu'en est-il des analyses de données et des tags de commande? Les Functions peuvent-elles écrire des données?
Les Functions ne peuvent pas écrire de tags de commande ni déclencher de webhooks — elles renvoient uniquement des opérations sur le panier en cours. Pour le taggage ou les flux de travail en aval, utilisez Shopify Flow déclenché par l'événement de création de commande. De nombreux marchands associent une Function (pour la remise) à un Flow (pour ajouter le tag « VOLUME-DISCOUNT-APPLIED » sur la commande).
Existe-t-il une application publique que je peux installer au lieu de développer une Function personnalisée?
Oui — le Shopify App Store propose des dizaines d'applications qui intègrent des Functions pour les cas d'usage courants. Recherchez « discount function », « delivery customization » ou « payment customization ». Pour des besoins classiques (remises sur volume, masquage de paiement par tag, livraison gratuite dès X $), une application existante peut vous éviter des jours de développement. Réservez les Functions personnalisées aux logiques réellement spécifiques à votre activité.
Que se passe-t-il si je dépasse la date limite du 30 juin?
Le Script s'arrête — il n'y a pas de solution de repli, pas de période de grâce et aucun report possible. Quelle que soit la fonction du Script (remise, masquage de tarif de livraison, blocage de paiement), le comportement par défaut sera rétabli à minuit UTC le 1er juillet. Si votre activité dépend de cette logique, prévoyez d'être opérationnel bien avant cette date. La migration prend généralement plus de temps que prévu, notamment en raison des tests de parité.
Puis-je supprimer définitivement l'application Script Editor?
Vous pourrez la désinstaller après le 30 juin 2026, mais Shopify la retirera probablement d'office. Une fois que les Scripts ne s'exécutent plus, l'éditeur n'a plus d'utilité. Vous pouvez également désactiver tous vos Scripts dès maintenant et désinstaller l'application immédiatement si votre migration est terminée — vos Functions fonctionnent de manière autonome.
Ce qu'il faut faire cette semaine
Ne vous contentez pas de lire cet article. Réalisez ces quatre actions dans les sept prochains jours.
1. Récupérer le Customizations Report. Allez dans Settings → Checkout → Customizations Report. Exportez-le. C'est votre base de travail pour la migration.
2. Configurer votre environnement de dev. Installez Node 18+, la Shopify CLI et Rust (si nécessaire). Vérifiez que shopify version fonctionne. Durée estimée : 30 minutes.
3. Générer et déployer une petite Function sur une boutique de dev. Choisissez le Script le plus simple — souvent une règle de masquage de paiement. Migrez-le de bout en bout. Même s'il ne va pas en production, vous aurez validé votre environnement de travail.
4. Bloquer des créneaux dans votre calendrier pour les huit prochaines semaines. Une migration ne se fait pas à la va-vite entre deux tâches quotidiennes. Réservez des plages régulières — par exemple chaque mardi et jeudi après-midi — et traitez ce projet comme une priorité absolue.
Parmi les équipes que nous avons accompagnées, le schéma reste le même : deux semaines d'attente, trois semaines de développement réel, une semaine de finalisation. Cela représente six semaines. Il vous en reste dix. Profitez de cette marge pour la revue de code et l'assurance qualité, sans repousser le lancement du projet.
Et une fois la logique de paiement opérationnelle, l'étape suivante pour la plupart des marchands est le post-achat — modifications d'adresses, échanges d'articles ou ajouts de remises après commande. Si cela fait partie de vos projets (et cela devrait être le cas, que vous soyez un marchand Plus à fort volume ou une boutique Advanced axée sur l'expérience client), Revize est disponible sur le Shopify App Store et fonctionne en parfaite synergie avec toutes les Functions que vous développerez.
Ressources
Articles connexes
Shopify Checkout Extensibility 2026: You Missed the Deadline. Now What?
The Universal Commerce Protocol (UCP): What Every Shopify Developer Needs to Know
Best Shopify Customer Service Apps for 2025 (Tested & Ranked)
Mis à jour en août 2026. Revize est une application Shopify permettant aux clients de modifier eux-mêmes leurs commandes après l'achat. Elle permet aux acheteurs de modifier leur adresse de livraison, d'échanger une variante ou un produit, d'annuler et d'obtenir un remboursement ou un avoir avant le traitement de la commande, le tout sans ouvrir de ticket d'assistance. En savoir plus sur la possibilité de permettre aux clients de modifier leurs propres commandes Shopify, ou retrouver Revize sur le Shopify App Store.
Nous sommes le 16 avril 2026. Hier, le 15 avril, Shopify a verrouillé définitivement le Script Editor. Vous ne pouvez plus créer ni publier de nouveau Script. Cette échéance est particulièrement critique pour la logique post-achat : les modifications d'adresse de livraison représentent la modification post-achat numéro 1, comptant pour 30.2 % de toutes les commandes modifiées (Revize, 2026), et tout Script gérant encore ces modifications est désormais figé. L'arrêt complet de l'exécution intervient dans 75 jours, le 30 juin 2026.
Si vous êtes un développeur Shopify Plus — ou l'agence gérant 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 secondaire. Un problème du type « votre passage à la caisse plante à minuit le 1er juillet ». La plupart des boutiques Plus ont accumulé entre 5 et 20 Scripts au fil des ans, chacun gérant discrètement une règle de remise, un masquage de livraison ou une passerelle de paiement que personne ne se rappelle avoir codé.
Ce guide est le manuel de migration technique 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 structurer une Function avec la Shopify CLI, écrire la logique en Rust ou JavaScript pour les remises, les personnalisations de livraison et de paiement, la tester en toute sécurité sur un sous-ensemble ciblé de vos clients, et la déployer en production sans perturber votre processus d'achat actuel.
Retirons les Scripts de votre boutique et installons 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 (remises, 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 la seule méthode de personnalisation prise en charge par Shopify à l'avenir.
Ce qui change réellement le 30 juin
Avant de toucher au code, clarifions les dates. Il y en a deux, et les deux sont cruciales.
Date | Ce qui se passe | Votre action |
|---|---|---|
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 passage à la caisse continue de fonctionner, soit elle ne l'est pas — et chaque panier concerné revient silencieusement aux tarifs standards, aux modes de livraison par défaut et à l'activation de toutes les méthodes de paiement. 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écute plus.
Conseil : Allez dans
Settings → Checkout → Customizations Reportdans votre admin Shopify. Vous y trouverez la liste de tous les Scripts actifs sur votre boutique, leur rôle et le type de Function de remplacement recommandé. Commencez par là.
Functions vs Scripts : Ce qui a changé
Dimension | Shopify Scripts (obsolète) | Shopify Functions (remplacement) |
|---|---|---|
Langage | Ruby DSL (spécifique à Shopify) | Rust, JavaScript, TypeScript |
Runtime | Ruby sandboxé sur l'infra Shopify | WebAssembly (WASM) — exécution < 5 ms |
Disponibilité forfait | Plus uniquement | Tous les forfaits (les applications personnalisées nécessitent Plus ; les applications publiques sont ouvertes) |
Éditeur | Script Editor dans l'admin | IDE local + Shopify CLI |
Contrôle de version | Aucun — modifications en direct | Compatible Git — contrôle de version complet |
Tests | Manuels dans le processus d'achat | Développement local avec |
Déploiement | Clic sur « Enregistrer » dans l'admin |
|
Cibles | Articles, livraison, paiements | Remises, Cart Transform, Validation, Delivery Customization, Payment Customization, Order Routing, Fulfillment Constraints, et plus |
Le changement d'architecture est majeur. Les Scripts consistaient à « modifier du Ruby dans une zone de texte ». Les Functions consistent à « écrire une véritable application, la soumettre au contrôle de version, la tester localement, la déployer via un vrai pipeline CI ». La courbe d'apprentissage est plus raide. C'est aussi la dernière migration de logique de paiement que vous ferez à moyen terme — les Functions représentent l'engagement à long terme de Shopify, pas une solution temporaire comme l'ont été les Scripts.
Associer vos Scripts au bon type de Function
Chaque Script actuel correspond à une API de Function spécifique. Voici le tableau de correspondance à garder sous les yeux.
Ancien type de Script | Rôle | Nouvelle API de Function | Cible de la Function |
|---|---|---|---|
Line Item Script | Appliquer des remises à des produits / clients / conditions de panier spécifiques | Cart & Checkout Discounts API |
|
Shipping Script (remise) | Livraison gratuite / remisée selon les règles du panier | Cart & Checkout Discounts API |
|
Shipping Script (masquer / renommer / réordonner) | Masquer un tarif de livraison 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 méthodes | Payment Customization API |
|
Script modifiant le panier (rare) | Regrouper des produits, remplacer des articles | Cart Transform API |
|
Script de blocage de commande | Rejeter le panier si le mélange de SKU est invalide | Cart & Checkout Validation API |
|
Si vous avez dix Scripts, vous développerez probablement trois à cinq Functions — plusieurs Scripts se regroupent souvent en une seule Function dotée d'une logique d'embranchement plus propre.

Prérequis : Configurer votre environnement de développement local
Avant de générer une Function, vous devez installer trois outils localement. 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 depuis 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 des 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 augmente la charge 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éploirez les Functions avant de les passer en production.
Générer votre première Function
La CLI génère la majeure partie du code de base. Dans n'importe quel répertoire :
# Créer une nouvelle application Shopify (ignorer 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 les étapes. Pour une Function de remise, vous choisirez :
Type: Function
Template:
discount(oucart_checkout_validation,delivery_customization,payment_customization, etc.)Language: Rust ou JavaScript
Name: quelque chose comme
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 constamment 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 offrait 10 % de réduction 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 avec une 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 } }
Conseil : Les Functions ne voient que les données que vous demandez. Gardez le GraphQL minimal — chaque champ omis permet 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> { // Sortie 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![] }); } // Somme des 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 # Une fois prêt, déployez shopify app deploy # Dans le panneau GraphiQL qui s'ouvre (appuyez sur `g` dans le terminal de dev), # créez la remise automatique qui utilise votre Function :
mutation { discountAutomaticAppCreate( automaticAppDiscount: { title: "Volume Discount (5+ collection items)" functionHandle: "volume-discount-fn" discountClasses: [ORDER] startsAt: "2026-04-16T00:00:00Z" } ) { automaticAppDiscount { discountId } userErrors { field message } } }
C'est tout. La Function est active, soumise au contrôle de version et remplace complètement l'ancien Script.
Tutoriel 2 : Remplacer un Shipping Script (Masquer une méthode au-dessus d'un seuil de panier)
Un Script classique : « Masquer la livraison Express lorsque le sous-total du panier dépasse 500 $ pour éviter des envois urgents coûteux sur de grosses commandes ». Voici la version Function de type Delivery Customization.
Étape 2.1 : Génération du code
shopify app generate extension --template delivery_customization --name hide-express-fn
Étape 2.2 : Requête d'entrée (src/run.graphql)
query Input { cart { cost { subtotalAmount { amount } } deliveryGroups { deliveryOptions { handle title } } } }
Étape 2.3 : Logique (src/run.js — variante JavaScript)
// @ts-check /** * @typedef {import("../generated/api").RunInput} RunInput * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult */ const NO_CHANGES = { operations: [] }; const THRESHOLD = 500.0; const HIDE_TITLES = ["Express", "Overnight"]; /** * @param {RunInput} input * @returns {FunctionRunResult} */ export function run(input) { const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount); if (subtotal < THRESHOLD) return NO_CHANGES; const operations = input.cart.deliveryGroups.flatMap((group) => group.deliveryOptions .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t))) .map((opt) => ({ hide: { deliveryOptionHandle: opt.handle }, })) ); return { operations }; }
Étape 2.4 : Activation via l'Admin (aucune mutation GraphQL requise)
Les Delivery Customizations disposent d'une interface d'administration intégrée. Après shopify app deploy :
Allez dans Settings → Shipping and delivery
Faites défiler jusqu'à la section Customizations 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 pour tout client ayant le tag 'B2B' ». Voici la version Payment Customization.
Étape 3.1 : Génération du code
shopify app generate extension --template payment_customization --name hide-cod-b2b-fn
Étape 3.2 : Requête d'entrée
query Input { cart { buyerIdentity { customer { hasTags(tags: [{ tag: "B2B" }]) { tag hasTag } } } } paymentMethods { id name } }
Étape 3.3 : Logique (src/run.js)
const NO_CHANGES = { operations: [] }; export function run(input) { const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0]; const isB2B = tagCheck?.hasTag === true; if (!isB2B) return NO_CHANGES; const codMethod = input.paymentMethods.find((pm) => pm.name.toLowerCase().includes("cash on delivery") ); if (!codMethod) return NO_CHANGES; return { operations: [{ hide: { paymentMethodId: codMethod.id } }], }; }
Étape 3.4 : Activation
Les Payment Customizations disposent également d'une interface d'administration sous 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 brève mise au point 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, changer de taille, corriger l'adresse de livraison ou appliquer une remise oubliée. Les Functions interviennent lors du passage à la caisse. Revize intervient après. Les Functions déterminent ce qui est autorisé dans le panier ; Revize permet à vos clients et à votre équipe support de modifier la commande après coup sans passer par un cycle d'annulation et de réédition. Cela compte pour deux types de boutiques : celles avec un volume de commandes tel que la modification manuelle devient impossible (les boutiques Plus, évidemment, 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 » nuit à la fidélisation.
Si votre plan de migration prévoit de passer des Scripts aux Functions mais que vous n'avez pas encore résolu la modification des commandes post-achat, vous vous heurterez rapidement à un autre obstacle. Le guide de gestion des commandes que nous venons de publier présente l'ensemble des bonnes pratiques post-achat.
Revenons à la migration.
Stratégie de test : La méthode des clients taggués
Les Functions n'ont pas de « mode brouillon » activable dans l'admin. La méthode professionnelle consiste à conditionner la nouvelle Function à un tag client, à exécuter l'ancien Script et la nouvelle Function en parallèle, à vérifier qu'ils produisent un résultat identique pour les utilisateurs taggués, puis à basculer définitivement.
Étape 1 : Taguez vos utilisateurs de test
Dans 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); // Passage à l'ancien Script existant } // La logique de la nouvelle Function s'exécute uniquement pour les utilisateurs taggués
Étape 3 : Ajoutez hasAnyTag à votre requête d'entrée
cart { buyerIdentity { customer { hasAnyTag(tags: ["FN-TESTER"]) } } }
Étape 4 : Vérifier dans le processus d'achat
Connectez-vous avec un compte taggué, passez commande, confirmez que la Function s'active. Connectez-vous avec un compte non taggué, confirmez que l'ancien Script s'exécute toujours. Une fois la parité validée sur quelques jours, retirez la vérification du tag pour appliquer la Function à tous.
Étape 5 : Désactiver l'ancien Script
Allez dans Apps → Script Editor → [Votre Script] → Unpublish. Une fois désactivé, la Function devient la seule source de vérité.
Workflow de déploiement évolutif
Ne déployez pas indéfiniment depuis l'ordinateur d'un développeur. Une fois un ou deux Scripts migrés, 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 jeton de partenaire depuis votre tableau de bord Partner sous Settings → Tokens. Désormais, chaque fusion sur main déploie vos Functions. Fini les discussions sur Slack pour savoir qui a déployé la dernière version.
Gestion des versions et retour arrière
shopify app deploy crée un instantané versionné. Pour revenir en arrière :
shopify app versions list shopify app release --version <previous-version-id
Par rapport aux Scripts — où le retour arrière nécessitait de retrouver l'ancien code pour le recoller — la différence est radicale.

Ce que la plupart des équipes ratent
Après avoir accompagné des marchands Plus dans cette migration l'année passée, les cinq mêmes erreurs reviennent systématiquement.
1. Traiter les Functions comme une simple copie conforme des Scripts. Ce n'est pas le cas. Une seule Function peut remplacer trois Scripts grâce à une logique d'embranchement plus propre. Analysez vos Scripts de manière globale avant de réécrire.
2. Oublier les scopes de lecture. De nombreuses Functions requièrent read_customers, read_orders ou write_discounts. Ajoutez-les dans shopify.app.toml sous scopes et ré-autorisez l'application, sinon votre requête d'entrée renverra null.
3. Lancer les Functions sur des clients non taggués sans test de parité. Même si votre code semble correct, des cas limites (panier vide, cartes-cadeaux, avoirs de boutique, brouillons B2B) révéleront des failles. Un déploiement progressif avec tag vous prend deux jours de plus mais vous évite une panne critique.
4. Ignorer le Customizations Report. C'est le meilleur inventaire de ce qui s'exécute réellement sur votre boutique. Ne migrez pas de mémoire — basez-vous sur ce rapport.
5. Hardcoder les IDs de collection et les tags clients. Utilisez la configuration de Function via les metafields si vous avez besoin de valeurs ajustables par le marchand. La CLI peut générer des configurations basées sur les metafields — consultez la documentation de Shopify à ce sujet.
Plan d'action pour les 75 prochains jours
Un planning réaliste pour aborder sereinement l'échéance du 30 juin.
Semaine | Action |
|---|---|
Semaine 1 (cette semaine) | Consulter le Customizations Report. Inventorier chaque Script. Décider entre Function, application publique ou suppression. |
Semaines 2–3 | Configurer l'environnement de développement local. Générer la première Function. Migrer le Script le plus simple (généralement une règle de masquage de paiement). |
Semaines 4–6 | Migrer les Scripts de remise. Ce sont ceux qui prennent le plus de temps car la Discounts API est la plus complète. Réaliser des tests approfondis par tag. |
Semaines 7–8 | Migrer les Scripts de livraison. Activer les Delivery Customizations via l'Admin. |
Semaines 9–10 | Configurer le pipeline CI. Automatiser tous les déploiements. |
Semaine 11 (mi-juin) | Vérification finale de parité. Désactiver tous les Scripts. Faire tourner la boutique uniquement avec les Functions pendant deux semaines. |
30 juin | Date butoir. Tout fonctionne car vous avez terminé en avance. |
Si vous commencez cette semaine, vous conservez une marge de sécurité. Si vous commencez en juin, vous n'en aurez pas.

Foire Aux Questions
Ai-je besoin de 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 choix s'offrent à vous : installer une application publique depuis le Shopify App Store qui déploie la Function pour vous, ou passer à Plus pour coder vos propres Functions personnalisées. La plupart des grands marchands utilisant des Scripts possédaient déjà Plus, ce qui ne change presque rien en pratique.
Puis-je écrire des Functions en TypeScript?
Oui — TypeScript est entièrement pris en charge et la CLI le configure pour vous. Lorsque vous lancez shopify app generate extension et choisissez « JavaScript », le projet généré inclut les déclarations de types de import("../generated/api"). Vous pouvez renommer les fichiers en .ts et ajouter un tsconfig.json si vous préférez. Le fichier compilé final (WASM) est strictement identique quel que soit le langage source.
Quelle est la rapidité des Functions par rapport aux Scripts?
Les Functions s'exécutent généralement en moins de 5 ms — soit nettement plus vite que les Scripts Ruby. Comme elles sont compilées en WebAssembly et s'exécutent dans un environnement restreint, Shopify impose une limite d'exécution de 5 ms. Si votre Function la dépasse, l'opération est abandonnée et la Function ne renvoie rien. En pratique, une Function bien conçue nécessite 1 à 2 ms. Les performances sont bien supérieures à celles des Scripts.
Une Function peut-elle appeler une API externe?
Non — les Functions ne peuvent pas effectuer de requêtes réseau. Il s'agit uniquement de calcul pur : données du panier en entrée → opérations en sortie. Si vous avez besoin de données externes (recherche CRM, vérification d'inventaire en temps réel), vous devez soit stocker ces données dans des metafields au préalable, soit utiliser une autre méthode (App Proxy, webhooks, Cart Transform avec appel back-end). C'est la raison la plus fréquente pour laquelle les équipes doivent repenser l'architecture plutôt que de faire un simple portage.
Quelle est la différence entre Cart Transform et les remises?
Les remises modifient les prix, tandis que Cart Transform modifie le contenu du panier. Utilisez la Discounts API pour appliquer un rabais de 10 %, offrir la livraison ou proposer une offre de type BOGO. Utilisez Cart Transform pour regrouper deux produits en un seul article, ou diviser une variante en plusieurs. De nombreux anciens Scripts mélangeaient ces deux aspects — lors de la migration, séparez-les en deux Functions distinctes.
Comment tester une Function localement sans boutique de développement?
Vous pouvez exécuter des tests unitaires avec cargo test (Rust) ou npm test (JS), mais les tests d'intégration complets requièrent une boutique de développement. La CLI propose shopify app function run qui exécute votre Function avec un fichier d'entrée de test — idéal pour itérer rapidement. Mais pour valider le comportement final du passage à la caisse de bout en bout, vous avez besoin d'une véritable boutique avec un panier réel.
Puis-je avoir plusieurs Functions du même type?
Oui — Shopify prend en charge plusieurs Functions par cible, et elles s'exécutent dans un ordre déterminé. Pour les remises, l'ordre est régi par les règles de cumul de Shopify. Pour les Delivery et Payment Customizations, vous pouvez chaîner les Functions, la sortie de l'une alimentant l'entrée de la suivante. La plupart des équipes utilisent une seule Function par type pour simplifier la gestion.
Qu'advient-il de mon Script après le déploiement de la Function?
Les deux s'exécutent en parallèle jusqu'à ce que vous désactiviez le Script dans Apps → Script Editor. Cela est intentionnel et vous permet de réaliser vos tests en conditions réelles. Après validation de la Function, désactivez manuellement le Script. Après le 30 juin 2026, tous les Scripts cesseront de s'exécuter, qu'ils soient désactivés ou non.
La 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 à la caisse et n'interfèrent jamais avec votre thème ou vos pages produits. Elles modifient uniquement les remises, les options de livraison et les méthodes de paiement lors du paiement. Votre boutique en ligne, vos fiches produits et votre SEO restent inchangés.
Comment migrer un Script qui utilise Input.line_items avec des propriétés personnalisées?
Les propriétés personnalisées sont accessibles via le champ attribute des lignes du panier dans l'entrée GraphQL. Ajoutez attribute(key: "votre-cle") { value } dans la sélection lines. La Function les lit de la même manière que les Scripts lisaient les propriétés d'articles, mais via GraphQL plutôt que par des appels de méthodes Ruby.
Qu'en est-il des analyses de données et des tags de commande? Les Functions peuvent-elles écrire des données?
Les Functions ne peuvent pas écrire de tags de commande ni déclencher de webhooks — elles renvoient uniquement des opérations sur le panier en cours. Pour le taggage ou les flux de travail en aval, utilisez Shopify Flow déclenché par l'événement de création de commande. De nombreux marchands associent une Function (pour la remise) à un Flow (pour ajouter le tag « VOLUME-DISCOUNT-APPLIED » sur la commande).
Existe-t-il une application publique que je peux installer au lieu de développer une Function personnalisée?
Oui — le Shopify App Store propose des dizaines d'applications qui intègrent des Functions pour les cas d'usage courants. Recherchez « discount function », « delivery customization » ou « payment customization ». Pour des besoins classiques (remises sur volume, masquage de paiement par tag, livraison gratuite dès X $), une application existante peut vous éviter des jours de développement. Réservez les Functions personnalisées aux logiques réellement spécifiques à votre activité.
Que se passe-t-il si je dépasse la date limite du 30 juin?
Le Script s'arrête — il n'y a pas de solution de repli, pas de période de grâce et aucun report possible. Quelle que soit la fonction du Script (remise, masquage de tarif de livraison, blocage de paiement), le comportement par défaut sera rétabli à minuit UTC le 1er juillet. Si votre activité dépend de cette logique, prévoyez d'être opérationnel bien avant cette date. La migration prend généralement plus de temps que prévu, notamment en raison des tests de parité.
Puis-je supprimer définitivement l'application Script Editor?
Vous pourrez la désinstaller après le 30 juin 2026, mais Shopify la retirera probablement d'office. Une fois que les Scripts ne s'exécutent plus, l'éditeur n'a plus d'utilité. Vous pouvez également désactiver tous vos Scripts dès maintenant et désinstaller l'application immédiatement si votre migration est terminée — vos Functions fonctionnent de manière autonome.
Ce qu'il faut faire cette semaine
Ne vous contentez pas de lire cet article. Réalisez ces quatre actions dans les sept prochains jours.
1. Récupérer le Customizations Report. Allez dans Settings → Checkout → Customizations Report. Exportez-le. C'est votre base de travail pour la migration.
2. Configurer votre environnement de dev. Installez Node 18+, la Shopify CLI et Rust (si nécessaire). Vérifiez que shopify version fonctionne. Durée estimée : 30 minutes.
3. Générer et déployer une petite Function sur une boutique de dev. Choisissez le Script le plus simple — souvent une règle de masquage de paiement. Migrez-le de bout en bout. Même s'il ne va pas en production, vous aurez validé votre environnement de travail.
4. Bloquer des créneaux dans votre calendrier pour les huit prochaines semaines. Une migration ne se fait pas à la va-vite entre deux tâches quotidiennes. Réservez des plages régulières — par exemple chaque mardi et jeudi après-midi — et traitez ce projet comme une priorité absolue.
Parmi les équipes que nous avons accompagnées, le schéma reste le même : deux semaines d'attente, trois semaines de développement réel, une semaine de finalisation. Cela représente six semaines. Il vous en reste dix. Profitez de cette marge pour la revue de code et l'assurance qualité, sans repousser le lancement du projet.
Et une fois la logique de paiement opérationnelle, l'étape suivante pour la plupart des marchands est le post-achat — modifications d'adresses, échanges d'articles ou ajouts de remises après commande. Si cela fait partie de vos projets (et cela devrait être le cas, que vous soyez un marchand Plus à fort volume ou une boutique Advanced axée sur l'expérience client), Revize est disponible sur le Shopify App Store et fonctionne en parfaite synergie avec toutes les Functions que vous développerez.
Ressources
Articles connexes
Shopify Checkout Extensibility 2026: You Missed the Deadline. Now What?
The Universal Commerce Protocol (UCP): What Every Shopify Developer Needs to Know
Best Shopify Customer Service Apps for 2025 (Tested & Ranked)
Mis à jour en août 2026. Revize est une application Shopify permettant aux clients de modifier eux-mêmes leurs commandes après l'achat. Elle permet aux acheteurs de modifier leur adresse de livraison, d'échanger une variante ou un produit, d'annuler et d'obtenir un remboursement ou un avoir avant le traitement de la commande, le tout sans ouvrir de ticket d'assistance. En savoir plus sur la possibilité de permettre aux clients de modifier leurs propres commandes Shopify, ou retrouver Revize sur le Shopify App Store.
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



