Shopify Scripts Are Gone: Migrating to Functions
Scripts ran in a sandbox on Shopify's servers and could be edited in the admin. Functions are compiled WebAssembly modules deployed as an app. That difference shapes the whole migration.

On this page
Key takeaways
- Legacy Shopify Scripts stopped running on 30 June 2026, so this is a completed deprecation rather than an upcoming one.
- Functions are compiled WebAssembly deployed through an app, which means version control and a deployment step where Scripts had neither.
- The migration is rarely a translation — Functions have a different execution model, and logic that worked in a Script often needs restructuring rather than porting.
- Shipping and payment customisations migrate to their own Function APIs, not to the discount one, and are commonly forgotten.
Shopify Scripts stopped running on 30 June 2026. If you are reading this because something broke, the answer is that nothing broke — a deprecation completed on schedule, and the failure mode was silence rather than an error.
That silence is the reason this deprecation caused more damage than it should have. A Script that stops running does not throw. Discounts simply stop applying, orders complete at full price, and unless someone was watching order-level margin closely, nothing surfaces for weeks.
If you are unsure whether this affects you
Check whether your store ever had Script Editor installed, and look at whether any expected automatic discount is currently failing to apply. Absence of errors is not evidence that nothing is wrong here.
What actually changed
Scripts and Functions solve the same problem with fundamentally different architecture, and understanding the difference explains why migration is more than a translation exercise.
Scripts and Functions compared
| Shopify Scripts | Shopify Functions | |
|---|---|---|
| Language | Ruby | Rust or JavaScript, compiled to WebAssembly |
| Availability | Plus only | Discount Functions available beyond Plus |
| Editing | In the admin, via Script Editor | Code in a repository, built and deployed |
| Deployment | Save and it is live | Build, deploy through an app, then configure |
| Execution | Sandboxed at runtime | WebAssembly at defined extension points |
| Version control | None | Whatever your repository provides |
| Performance | Variable | Fast and bounded by design |
The two rows that change how teams work are editing and deployment. Scripts could be modified by anyone with admin access, in the browser, and were live on save. That was genuinely convenient and genuinely dangerous — there was no history, no review, and no way to know who changed pricing logic or when.
Functions invert this. You get version control, review and repeatability. You also get a deployment step, which means the merchant who used to adjust a discount rule themselves on a Friday afternoon now files a ticket.
The migration is restructuring, not porting
The common expectation is that a Script can be translated line by line. It usually cannot, because the execution model differs.
A Script ran with broad access and could iterate over the cart making decisions procedurally. A Function receives a defined input, produces a defined output, and runs at a specific extension point with limits on what it can see and how long it may take. Logic written against the first model frequently needs to be re-expressed rather than converted.
Three patterns that tend to need rethinking:
Multi-pass cart logic. Scripts that walked the cart repeatedly, adjusting as they went, need restructuring into a single evaluation producing a set of discount operations.
Decisions requiring data the Function cannot see. A Script that consulted broad shop state may need that data supplied through metafields, which the Function receives as input. This is often the largest piece of the work and is easy to underestimate.
Interdependent Scripts. Stores commonly ran several Scripts that assumed a particular execution order. Functions do not offer the same implicit sequencing, and overlapping logic must be made explicit.
Do not forget shipping and payment
This is the most common oversight in the migration, and it is expensive because it is discovered at checkout.
Scripts covered three areas: line item discounts, shipping rates, and payment method behaviour. Merchants migrating tend to focus on discounts, because that is the visible commercial feature, and forget that their Script also hid a payment method from certain customers or renamed a shipping rate.
Each of these has its own Function API — discounts, delivery customisation and payment customisation are separate extension points, not variations of one. Audit for all three before scoping the work:
Audit before you scope
- Every discount rule the Script applied, including edge cases nobody documented
- Any shipping rate hidden, renamed or reordered
- Any payment method hidden or reordered by customer, cart or address
- Conditions referencing customer tags, metafields or order history
- Behaviour depending on the order in which multiple Scripts ran
- Anything only triggered seasonally, which will not be visible in a current audit
That final item catches teams out. A Script handling a Christmas promotion is invisible in a July audit and absent when November arrives, which is the worst possible moment to discover it.
Who can change discount logic now
This is an organisational consequence that deserves explicit planning, because it is the change merchants feel most.
Under Scripts, a merchant could adjust a threshold themselves. Under Functions, the logic is compiled. There are two ways to restore merchant control, and choosing between them should be a deliberate decision made during the migration rather than discovered afterwards:
Configuration through metafields. Build the Function to read its parameters — thresholds, product sets, dates — from metafields, and expose those in the admin. The logic is fixed; the numbers are editable. This covers most real needs and is the right default.
A full app interface. Build an embedded admin interface for configuring offers. More work, more flexibility, and effectively what commercial discount apps sell.
If you migrate a Script into a hardcoded Function without either, you will have converted every future pricing tweak into a development ticket. That is a common and avoidable outcome.
A migration sequence that does not break checkout
- Inventory everything. Every Script, every rule, every edge case. Interview whoever configured them, because the code frequently does not explain the intent.
- Write down the intended behaviour in plain language, separately from the code. This is the specification you will test against, and it will expose rules nobody can justify any more.
- Decide what stays. Migration is a good moment to delete rules that exist because of a promotion in 2023. Porting logic nobody wants is pure cost.
- Build the Functions, with configuration exposed through metafields where merchants need control.
- Test combinations exhaustively, including accelerated checkouts and every case where two rules could apply at once.
- Deploy and verify on real orders, watching order-level margin for the first week rather than assuming success.
Test with real historical carts
Take twenty genuine past orders that the old Scripts affected and confirm the new Functions produce the same outcome. This catches the edge cases that a specification written from memory will miss, and it is far cheaper than finding them in production.
The failure modes to watch for after deploying
A Function that deploys successfully is not a Function that behaves correctly, and the ways these go wrong are specific enough to be worth listing.
Silent non-application. The most common and the most costly. The Function runs, produces no discount operation because a condition was subtly wrong, and the order completes at full price. There is no error anywhere. The only signal is margin that looks slightly too good, which nobody investigates.
Over-application. The inverse, and easier to spot because someone eventually notices the revenue. Usually caused by a condition that was implicitly scoped in the old Script by surrounding code and is now evaluated independently.
Correct in the cart, wrong at checkout. Rarer with Functions than with cart-manipulating apps, but still possible where storefront messaging is computed separately from the actual discount. If your theme displays a calculated saving, that calculation is a second implementation of the same logic and the two will drift.
Timeouts under load. Functions run within bounded execution limits. Logic that is comfortable on a five-item cart may not be on a fifty-item one, and the carts that break are disproportionately your largest orders.
Metafield drift. If you exposed configuration through metafields, someone will eventually enter a value the Function does not handle — a blank threshold, a deleted product reference, a date in the wrong format. Validate inputs inside the Function and decide explicitly what it does with nonsense, because the default is usually to apply nothing.
Instrument before you need it
Add a monitor on the proportion of orders receiving each expected discount, and alert when it moves sharply. This is the only reliable defence against silent non-application, and it costs an afternoon. Every merchant who lost money to the Scripts deprecation lost it because nothing was watching this number.
What you gain, honestly
The migration is unwelcome work, but the destination is better in ways worth stating.
Functions are faster and more predictable than Scripts were, and they run within defined limits rather than variably. Discount Functions extend beyond Plus, which widens what non-Plus merchants can do. And the deployment model, whatever it costs in convenience, means pricing logic now lives in version control with a history — which is a substantial improvement over a system where anyone with admin access could silently change how your store charges people.
The convenience loss is real and should be mitigated rather than denied. Build for configuration, not just for behaviour, and the merchant keeps the control that mattered while you keep the review that was missing.
For the wider development picture on Shopify, see Shopify development. Discount strategy and mechanics are covered in promotions and offers, and checkout behaviour in checkout and payments.
Frequently asked questions
- When exactly did Shopify Scripts stop working?
- Legacy Shopify Scripts stopped running on 30 June 2026.
- What is the difference between Shopify Scripts and Shopify Functions?
- Scripts were Ruby, edited in the admin through the Script Editor, available only to Plus merchants, and executed in a sandbox at runtime.
- Do I need to be on Shopify Plus to use Functions?
- Discount Functions are available beyond Plus, which is a meaningful widening compared with Scripts. Some extension points and higher input limits remain tied to Plus.
- Can I edit a Function in the Shopify admin like I could a Script?
- No, and this is the largest workflow change. A Function is code in a repository that must be built and deployed.
- What happens to my discounts if I do nothing?
- They stopped applying on 30 June 2026.



Comments