Shopify Functions vs Script Editor: the migration most stores haven't started

Shopify is winding down Script Editor in favour of Shopify Functions. Here's what's changed, what to migrate first, and the gotchas we keep hitting.

Script Editor has been on Shopify Plus for years — it’s how Plus merchants wrote custom logic for discounts, shipping, and payment methods. Shopify is shifting all of that to Shopify Functions, and a surprising number of Plus stores still haven’t started the migration.

Here’s the short version of what’s happening and what to do.

What’s changing

Script Editor scripts ran inside Shopify’s checkout, in a Ruby-like sandbox. Shopify Functions run at the platform edge, in WebAssembly, written in Rust or JavaScript.

The shift is partly performance, partly security, partly that Functions integrate with the rest of the Extensibility model (Branding API, UI Extensions). Script Editor was a legacy island; Functions live in the new continent.

Practically:

  • Discount Scripts → Discount Functions
  • Shipping Scripts → Delivery Customization Functions
  • Payment Scripts → Payment Customization Functions

What you can do that you couldn’t before

A few wins:

  • Functions can read more data — including line item properties, customer metafields, cart attributes — without the workarounds Script Editor needed.
  • Functions are testable. You write JS or Rust unit tests against fixtures. Script Editor was effectively impossible to test.
  • Functions ship via Shopify CLI. Version-controlled, reviewable, deployable like any other code.
  • Multiple Functions can stack. You can run several discount Functions in parallel; Script Editor was one-script-at-a-time.

What you can’t do anymore

  • Free-form Ruby scripting. Functions are constrained to a typed input/output contract. If your old script reached into customer history or did anything weirdly stateful, you’ll need to redesign.
  • Side effects. Functions are pure — input → output. If your old script wrote to a customer tag mid-checkout, that has to move to a webhook flow.
  • Real-time external API calls. Functions don’t make network requests. If your discount logic needed to check a third-party fraud service, that has to happen earlier in the funnel.

A typical migration

Most Plus stores have 1–3 active scripts. Here’s a path that works:

  1. Inventory your scripts. For each, write a one-line description of what it does.
  2. Categorise. Discount, Shipping, Payment, or “weird custom thing.”
  3. Start with Discount. It’s the highest-touch area and the migration is cleanest.
  4. Fork your theme. You’ll be testing in a Shopify CLI app project, not the theme — but verify the discount renders correctly in the cart and checkout.
  5. Deploy to a draft store. Run a real test order. Confirm the discount applies.
  6. Cutover. Disable the Script in admin, deploy the Function. Watch orders for 48 hours.
  7. Repeat for shipping and payment.

Gotchas we’ve hit

  • Cart attributes don’t auto-pass to Functions. If your script read a custom attribute, the Function needs to explicitly request it via the input query.
  • Decimals. Functions use a different money representation. Don’t assume direct port works for percentage discounts.
  • Tag-based logic. Customer tags now go through an explicit query — make sure the tags you’re checking exist on the customer when the cart is created.
  • Subscription apps. If a subscription app inserts items into the cart, your Function may run before or after — test both states.

Should you wait?

No. Shopify is migrating Plus stores actively, and stores that aren’t migrating get on the wrong side of the platform’s roadmap. Functions are also genuinely better long-term — your future self will thank you for not having a year-old Script Editor liability.

If your team can’t do the migration, a Shopify Plus partner who’s done it five times can knock out a typical store in a couple of days.

— Read next

Why your Shopify store loads slow — and the seven things that almost always fix it

— Hit a wall?

We can help building properly?