Shopify Scripts Die June 30 2026: Migrate to Functions

I have three live Plus stores running Ruby Shopify Scripts in production this week. All three lose checkout logic on June 30 2026. The Script Editor app already locked publishing on April 15 2026. The clock is loud.

TL;DR: Shopify Scripts stop firing June 30 2026. Publishing is already frozen as of April 15 2026. Migrate Line Item Scripts to Discount Functions, Payment Scripts to Payment Customization Functions, Shipping Scripts to Delivery Customization Functions. Functions are JavaScript or Rust on WebAssembly, shipped as a Shopify app via the CLI. A typical Plus store finishes in 8 weeks.

Why this matters for your store

  • Every silent Script failure on July 1 2026 ships orders at full price, with the wrong payment methods, and the wrong shipping label.
  • Plus merchants leaning on tag-based B2B pricing or tiered free shipping carry the heaviest migration load.
  • The 60-day window from this post’s date closes the buffer. Audit week one or build a buffer week into a delayed sprint.

When exactly do Shopify Scripts stop working?

June 30 2026 is the sunset. April 15 2026 was the publish freeze. If you missed the freeze, your old Scripts still run, but you cannot deploy a new one, fix a bug, or change a threshold. Whatever shipped before April 15 is what runs until June 30.

Shopify pushed this deadline twice already, from August 2024 to August 2025 to June 2026. The platform team has confirmed the third push is the last. The Script Editor app, the Ruby runtime, and the legacy script.rb execution path are all being removed.

The failure mode is the worst kind for revenue. Scripts will not throw a checkout error. They will simply stop. Your $150 free shipping rule stops applying. Your “hide PayPal for B2B” rule stops hiding. Your free-gift threshold stops adding the gift. Customers complete checkout at full price, and your support inbox lights up Tuesday morning.

I am running three migrations this quarter. One Line Item Script (a 20% wholesale tag override), one Payment Script (hide PayPal Express for B2B), one Shipping Script (free over $150 rename). The playbook below is the order I am running them.

What replaces Shopify Scripts?

Shopify Functions replace Shopify Scripts. Functions are deterministic WebAssembly modules written in JavaScript or Rust, scaffolded with the Shopify CLI, deployed as Shopify apps, and executed at the edge during cart and checkout. There are seven Function APIs as of writing. The three that matter for Scripts are Discount, Payment Customization, and Delivery Customization.

The shape is fundamentally different. A Script mutates Input.cart in place. A Function is a query plus a result. You declare a GraphQL input query, write a pure handler that returns a result object, and Shopify applies that result to the cart. The query caches. The handler runs in WebAssembly with a hard execution budget. That is why Functions scale through BFCM where Scripts hit per-request rate limits.

Script type Function replacement Plan availability
Line Item Script Discount Function All paid plans
Payment Script Payment Customization Function Plus only
Shipping Script Delivery Customization Function Plus only

Discount Functions ship on Basic, Shopify, and Advanced. Payment and Delivery Customization stay Plus-only, mirroring the Scripts model. For broader context, the Shopify Plus checkout optimization guide covers the August 26 2026 checkout.liquid deadline that sits next to this one. The Shopify Liquid development guide is the prerequisite for the theme side.

How does a Line Item Script become a Discount Function?

A Line Item Script that mutates Input.cart.line_items becomes a Discount Function with a cart.lines query and a product_discounts result. The Ruby logic moves into a JS run handler. The discount value moves from a direct line-item mutation to a returned discounts array. The discount registers as an automatic discount in the admin so it applies without a code.

For five real Plus-store Scripts to Functions ports with full code, see 5 Shopify Scripts I migrated to Functions. For the broader Plus checkout context, the Shopify Plus checkout optimization guide covers Checkout Extensibility, Web Pixels, and the Shop Pay component.

Here is the wholesale tag override I am migrating. Before, in Ruby:

class WholesaleDiscount
  def run(cart)
    return unless cart.customer&.tags&.include?("wholesale")
    cart.line_items.each do |li|
      d = li.line_price * Decimal.new(20) / 100
      li.change_line_price(li.line_price - d, message: "Wholesale 20% off")
    end
  end
end
WholesaleDiscount.new.run(Input.cart)
Output.cart = Input.cart

After, in JavaScript on a Discount Function (extensions/wholesale/src/run.js):

import { DiscountApplicationStrategy } from "../generated/api";
const EMPTY = { discountApplicationStrategy: DiscountApplicationStrategy.First, discounts: [] };

export function run(input) {
  const tags = input.cart.buyerIdentity?.customer?.hasTags;
  if (!tags?.some(t => t.tag === "wholesale" && t.hasTag)) return EMPTY;
  const targets = input.cart.lines
    .filter(l => l.merchandise.__typename === "ProductVariant")
    .map(l => ({ productVariant: { id: l.merchandise.id } }));
  if (!targets.length) return EMPTY;
  return { discountApplicationStrategy: DiscountApplicationStrategy.First,
    discounts: [{ targets, value: { percentage: { value: "20.0" } }, message: "Wholesale 20% off" }] };
}

Three things shifted. The customer-tag check moves into the GraphQL query (hasTags(tags: ["wholesale"])), so Shopify resolves it server-side before the handler runs. The discount applies as a percentage rather than a recomputed line price, which keeps {{ price | money }} clean across the theme. The discount appears as a discount line on the order summary rather than a mutated line price, which is cleaner for accounting and refunds.

How do Payment and Shipping Scripts map?

A Payment Script that hides, sorts, or renames payment methods becomes a Payment Customization Function with a paymentMethods query and a hide, move, or rename operation. A Shipping Script becomes a Delivery Customization Function with a cart.deliveryGroups.deliveryOptions query and the same operation set. Both are Plus-only on Scripts and Functions. The mapping is one-to-one.

The hide-PayPal-for-B2B Function is six lines of meaningful logic:

const NO_CHANGES = { operations: [] };
export function run(input) {
  const tags = input.cart.buyerIdentity?.customer?.hasTags;
  if (!tags?.some(t => t.tag === "b2b" && t.hasTag)) return NO_CHANGES;
  const paypal = input.paymentMethods.find(pm => /paypal/i.test(pm.name));
  return paypal ? { operations: [{ hide: { paymentMethodId: paypal.id } }] } : NO_CHANGES;
}

The Function executes once per cart-update event, not once per checkout render. That is a measurable performance win on Plus traffic. Scripts re-ran on every render, which is what fed the BFCM rate-limit complaints.

The free-shipping-over-$150 rename uses the same pattern with a rename operation keyed off cart.cost.subtotalAmount.amount. The threshold lives in code, version-controlled, deployed via shopify app deploy rather than pasted into the admin.

What is the 60-day migration plan?

Six steps across 60 days: audit, scope, scaffold, build, deploy, observe. The plan assumes a Plus store with one Line Item, one Payment, and one Shipping Script in production. That is the most common shape on the Plus stores I audit.

  • Week 1: Audit. Pull the Scripts deprecation report from the admin (Settings, Customer events). Export every active Script. Read every script.rb. Document the input, output, and business intent for each one. This is the work most teams skip and pay for in week 6.
  • Week 2: Scope. For each Script, decide build versus buy. Build a custom app when the logic references a customer tag, a metafield, or a threshold the merchant changes more than twice a year. Buy a third-party Function app for off-the-shelf rules with no custom branching.
  • Weeks 3 to 5: Scaffold and build. Run shopify app init, then shopify app generate extension --type=function per Function. Pick JavaScript unless your team is fluent in Rust. Write the GraphQL query first, the handler second, the unit tests third. The function-runner tool takes a JSON fixture and returns deterministic output, so every business rule pins to CI before deploy.
  • Week 6: Deploy and register. shopify app deploy ships to dev, then live. Register each Function in the admin (Discounts for Discount Functions, Settings, Payments, Customizations for Payment Functions, Settings, Shipping and delivery, Customizations for Delivery Functions). Disable the matching Script in the same maintenance window. Do not run both, because Scripts and Functions stack.
  • Week 7: Observe. Watch order tags, discount lines, and shipping option names for seven days. Wire a Shopify Flow trigger that pings Slack on any order with a missing customization. Compare the seven-day order log against the seven days under Scripts.
  • Week 8: Buffer. Reserve the final week for the one Script that turns out messier than the audit suggested. There is always one.

Start the audit the week this post lands and you finish with buffer before June 30 2026. I have run this exact rhythm on the WD Electronics Plus engagement and the custom MSRP and Compare At pricing logic on Factory Direct Blinds. Both landed inside 14 days of dev plus a one-week observation window.

What gets harder, and what gets easier?

Functions are harder to iterate on. A Script edit was a paste in the admin. A Function edit is a code change, a CLI deploy, and an automatic-discount or customization re-registration. You also lose puts debugging, since WebAssembly has no stdout. Plan the test setup up front, run function-runner locally with a JSON fixture, and read Function logs in the partner dashboard.

The wins compound on Plus traffic. Function code lives in your repo, every change is a reviewable commit, every business rule pins to a CI fixture, WebAssembly at the edge runs faster than the Ruby interpreter Scripts used. Functions also slot into Checkout Extensibility cleanly, so they survive checkout upgrades the same way Checkout UI Extensions do. Scripts were tied to the legacy script runtime, which is the runtime being removed on June 30.

The one trap to watch is discountApplicationStrategy (First, Maximum, All). Scripts mutated prices directly, so stacking was implicit. Functions return a strategy that interacts with code-based discounts and other Function discounts. Read the strategy docs before you assume a Function discount stacks the way the Script did, especially when you have a sitewide automatic discount layered with a code.

How to verify the migration

Three checks, five minutes each:

  1. Place a test order with a tagged customer, a payment method that should be hidden, and a cart that should rename shipping. Confirm the order summary shows the discount line, the hidden payment method is absent, and the shipping label is renamed.
  2. Pull the order in the admin and inspect the discount applications. The discount should reference the Function name, not “Script.”
  3. Run shopify app function run against the deployed Function with a JSON input fixture. Confirm the output matches the expected discount or operation list.

If any check fails, do not disable the matching Script. Roll back the Function registration, fix the handler, redeploy, retest.

The takeaway

  • Audit every active Script this week, not next sprint.
  • Map each Script to its Function counterpart using the one-to-one table above.
  • Build custom Function apps for tag, metafield, or threshold logic.
  • Ship Discount Functions first, then Payment and Delivery Customization.
  • Disable Scripts only after seven days of clean Function order data.

Need help migrating Scripts to Functions before June 30? Book a free 30-minute migration audit.

Frequently Asked Questions

When exactly do Shopify Scripts stop working?

Shopify Scripts stop executing on June 30 2026. Editing and publishing new Scripts is locked from April 15 2026, so the practical freeze is already in effect for any merchant reading this within 60 days of the cutoff. There is no opt-out, no per-store extension, and no carve-out for Plus. The deadline has already been pushed twice (from August 2024 to August 2025 to June 2026), and Shopify has confirmed this is the final move.

What replaces Shopify Scripts?

Shopify Functions replace Shopify Scripts. Line item Scripts move to Discount Functions, payment Scripts move to Payment Customization Functions, and shipping Scripts move to Delivery Customization Functions. Functions are deterministic WebAssembly modules written in JavaScript or Rust, deployed as Shopify apps, and executed at the edge. They scale better than Scripts, run faster, and survive checkout upgrades.

Are Shopify Functions Plus-only?

No. Discount Functions are available on every paid plan. Payment Customization, Delivery Customization, Cart Transform, and Order Routing Functions are Plus-only. So a non-Plus merchant migrating Line Item Scripts has a clean path via Discount Functions, but a Plus merchant migrating payment-method hiding or shipping-rate logic needs the Plus-tier Function APIs. The migration mapping below is the same regardless of plan.

Can I write a Function instead of installing a Function app?

Yes. Every Function is shipped as a Shopify app, but the app can be a private custom app you build for a single store. The Shopify CLI scaffolds the project, deploys the WebAssembly bundle, and registers the Function with the store. For most Plus merchants, that custom-app route is cleaner than installing a third-party Function app, since you keep the source code, the version history, and the deploy keys in your own repo.

How long does a Scripts to Functions migration take?

A single Line Item Script with a clear discount rule takes a senior dev one to two days end to end, including Function build, store deployment, automatic discount creation, and QA. A Payment or Shipping Script with branching logic takes three to five days. A full Plus store with one of each (line item, payment, shipping) typically lands in a 10 to 14 day sprint with QA, including a one-week observation window before the old Scripts are deactivated.

What breaks if I miss the June 30 2026 deadline?

Every active Shopify Script silently stops executing on June 30 2026. Discount Scripts no longer apply at checkout, so customers pay full price. Payment Scripts stop hiding payment methods, so customers see options the merchant intended to suppress. Shipping Scripts stop renaming or sorting rates, so the wrong shipping option may default. None of this triggers a checkout error. Orders complete at the wrong price or with the wrong logistics rule, which is the worst possible failure mode for revenue.

Should I migrate to a third-party Function app or build my own?

If your Script logic matches a feature an existing Function app already ships (Shopify Discounts app, Shop Circle, Mechanic, etc.) and the pricing works, install the app. If your logic is custom (B2B price override on a customer tag, threshold-based free gift, regional shipping override), build a custom Function app. The build path keeps the logic in your repo, which is the same place you already keep theme files, snippets, and merchant secrets.

Book Strategy Call