Shopify Scripts have quietly powered custom pricing, shipping and payment rules on Plus stores for years. They run in the Script Editor as Ruby, invisible to most of the team, and they tend to accumulate. Then the sunset notice arrives and nobody remembers what half of them do.

Functions replace Scripts, but they are not a copy-paste upgrade. They are WebAssembly modules deployed as app extensions, configured through metafields, and released with the Shopify CLI. A migration is a small engineering project, and like every deadline-driven project it goes badly when it is rushed and cleanly when it is inventoried first.

Abstract concept of logic migrating across a bridge of light from an old structure to a new crystalline one
A migration is a bridge, not a demolition. The old logic keeps running until the new logic proves itself.

01 · Deadline

Why this is not optional.

The Script Editor is tied to the legacy checkout. As stores move to checkout extensibility, the Ruby environment that runs your line-item, shipping and payment scripts goes away with it. There is no long-term "keep the old checkout" path—the extensibility migration and the Scripts sunset are the same road.

The risk is rarely the migration itself. The risk is discovering, on cutover day, that a three-line script from 2021 was silently suppressing an express shipping option for one region, or capping a wholesale discount. When it disappears, revenue moves in ways nobody predicted.

Treat every live script as production code with unknown blast radius until proven otherwise.

02 · Inventory

Map what your scripts actually do.

Before writing a single Function, write down every script that is currently published and, crucially, what business rule it enforces. Scripts fall into three families, and each maps to a different Function surface:

  • Line item scripts — discounts, tiered pricing, gift-with-purchase, volume breaks.
  • Shipping scripts — hiding, renaming or re-ranking delivery options.
  • Payment scripts — hiding or reordering payment methods by cart, customer or region.

For each one, record the trigger, the condition and the effect in plain language. "If cart contains a subscription item, hide cash on delivery" is a spec a Function author can build against. The raw Ruby is not—it hides intent behind implementation.

03 · Translate

Match each script to a Function API.

Functions are typed. You do not write one giant script; you pick the API that owns the behaviour and build a focused module. The common mappings:

  • Line-item discounts → Product / Order discount Functions, surfaced through the discounts system.
  • Shipping rule changes → Delivery customization Functions.
  • Payment method rules → Payment customization Functions.
  • Bundles and "buy X get Y" expansion → Cart transform Functions.
  • Blocking bad carts (max quantity, restricted mixes) → Cart and checkout validation Functions.

This is also the moment to consolidate. Five overlapping discount scripts often collapse into one or two well-structured Functions with clean configuration. We use Script Migrator to fingerprint the old scripts, cluster duplicates, and produce a per-Function spec so nothing is rebuilt twice.

Glowing geometric cubes flowing through a conduit and turning into polished crystals
Consolidation is the quiet win: tangled scripts become a handful of clean, testable Functions.

04 · Configure

Move settings into metafields.

Scripts hard-coded their thresholds—a magic number for the free-shipping floor, a region list, a discount percentage. Functions read configuration from metafields on the shop, product or discount, which is a genuine upgrade: merchandisers can change the free-shipping floor without a developer redeploying WebAssembly.

Design the configuration once. A single metaobject definition for "delivery rules" or "discount tiers" keeps the logic thin and the settings editable. It also means the Function itself rarely changes after launch—only the data does.

The best migration outcome is a Function so small it is boring, backed by configuration the merchant actually controls.

05 · Test

Prove parity before you cut over.

The migration is only safe when the new Function produces the same outcome as the old script for the same cart. Build a matrix of representative carts—each region, each customer tag, each edge case you found in the inventory—and run both paths in a development store.

  • Confirm discounts match to the cent, including how they combine.
  • Confirm shipping options appear, hide and rank identically.
  • Confirm payment methods surface for the right customers.
  • Confirm nothing new breaks: taxes, currency rounding, gift cards.

Functions run against the cart in the checkout, so test with real checkout sessions, not just the cart page. A rule that looks correct on the cart can behave differently once shipping is selected.

06 · Ship

Deploy without a checkout gap.

Deploy the app that holds your Functions, then activate each Function and its configuration in a controlled order. Discounts, delivery and payment customizations each have an activation step in the admin—turning the Function on is separate from deploying its code.

Where possible, run the new Function in parallel and only retire the old script once you have watched live orders confirm parity. Keep the old script's logic documented so that if a number looks wrong on day one, you can compare against the original intent instead of guessing.

Quick check

Ready to retire the Script Editor?

  • Every published script is documented as a business rule, not just Ruby.
  • Each rule is mapped to the correct Function API.
  • Thresholds and lists live in metafields, not hard-coded values.
  • A cart matrix proves parity across regions, tags and edge cases.
  • Activation order is planned so no checkout step goes dark.

Deadlines reward the prepared.

A Scripts migration is not glamorous, but it is exactly the kind of work that separates a store that keeps converting through a platform change from one that loses a week of orders to a rule nobody remembered. Inventory first, translate deliberately, configure for the merchant, and prove parity before you flip the switch. Done right, customers never notice a thing—which is the entire point.

Want this applied to your store?Let’s build something different.
Start a project