Shopify Functions vs Scripts: what changed after Scripts died
What the numbers say
- 01
Shopify Scripts stopped executing entirely on 30 June 2026.
- 02
Editing and publishing Shopify Scripts was frozen on 15 April 2026, before execution stopped.
- 03
A Shopify Function must complete its logic inside 11 million WebAssembly instructions or the run fails.
- 04
Function input is capped at 128 kB, which is why merchant configuration lives in metafields rather than in a payload.
- 05
Only 1 route exists for a Function to reach an external service at runtime, and it is restricted to custom apps on Plus and Enterprise stores.
- 06
Daily rotation of an offer turns 900 potential checkout-time lookups into 30 metafield writes a month.
Derived: one metafield write per daily rotation across 30 days, against a 900 order month.
- 07
A Function executes in under 5 milliseconds with no cold start, because it runs as compiled WebAssembly inside Shopify's platform rather than in a separately provisioned runtime.
What happened to Shopify Scripts on 30 June 2026?
Two dates ended Shopify Scripts. On 15 April 2026 editing and publishing stopped, so live Scripts kept running but could not be changed. On 30 June 2026 execution stopped entirely.
There was no fallback and no grace period. Checkout continued to work; the logic inside it did not.
Scripts were Ruby, ran in the Script Editor in the admin, and came in three types: line item, shipping, and payment. They were available on Shopify Plus only, for the whole of their life.
That last point decides how much of this matters to you. If your store was never on Plus, nothing broke on 30 June, because you never had a Script to lose.
Shopify Functions are the replacement for the logic Scripts carried. Native discount codes and automatic discounts in the admin were never part of this and still work exactly as before.
Shopify Scripts vs Shopify Functions: what actually differs
| Shopify Scripts | Shopify Functions | |
|---|---|---|
| Status | Stopped executing 30 June 2026 | Current and supported |
| Language | Ruby | Rust or JavaScript, compiled to WebAssembly |
| Where it lives | Script Editor in the admin | Inside a Shopify app, deployed through the CLI |
| Plan access | Plus only | Public Function apps on any plan; custom Function apps on Plus and Enterprise |
| Runtime input | The cart object | A GraphQL input query you declare, capped at 128 kB |
| Runtime network calls | None | None, apart from a fetch target restricted to Plus and Enterprise custom apps |
| Compute budget | Not documented for merchants | 11 million instructions per run |
| Behaviour | Ruby, edited in place | Pure: the same input returns the same output |
| Change process | Edit the text box, save | Build, deploy, release an app version |
The row that surprises people is the network one. Scripts could not call an external service either, so the sandbox is not new.
What changed is where the logic lives. A Script was a text box in your admin. A Function is an artifact inside an app, which means a deploy cycle, a version number, and usually a vendor between you and the rule.
Why the no-network rule is the constraint that shapes everything
A Function receives an input, runs, and returns operations. It cannot phone home in the middle.
One exception exists. A fetch target allows network access, and it is limited to custom apps on Plus and Enterprise stores, requires approval from Shopify, and does not work on development stores.
For any app that installs across plans, that exception is unavailable in practice. Treat runtime network access as absent and the design questions get much clearer.
Everything the discount depends on has to arrive through the input query. In practice that means three sources: metafields, cart attributes, and values hardcoded at build time.
The 128 kB input cap and the 11 million instruction budget then set the ceiling on how much of it you can carry and how much parsing you can afford. Large carts are where both limits get hit first.
What the no-network rule forces you to build instead
The architecture splits in two. A control plane outside Shopify decides what the current state is and writes it down. A data plane inside the Function reads that state and decides the discount.
State has to be written before checkout, not read during it. That single sentence explains most of the design decisions in any Function-based offer app.
The design question that follows is staleness tolerance. If your offer rotates daily, a metafield written once a day is exactly fresh enough, and the app makes 30 writes a month rather than resolving 900 checkouts against a live service.
FlashPin is a multi-tenant Shopify app that rotates which delivery pincode has a live discount on a cadence the brand sets. Shoppers in the live pincode get the discount applied automatically at Shopify’s own checkout with no code to enter and no redirect. Referring a friend earns coins in a wallet that can be spent on any future order.
The rotation clock sits in a Durable Object, outside the Function, and writes the live offer to a shop metafield. The Discount Function reads that metafield during checkout and never needs to ask anyone anything.
The second half of the design matters more than the first. The Function gates on cart.deliveryGroups[0].deliveryAddress.zip, which is Shopify’s own delivery address data.
The alternative is gating on a cart attribute, and cart attributes are writable by the shopper. Any offer gated on a value the buyer controls is a discount with a public key, which is a leak rather than a targeting mechanism.
FlashPin is not for multi-currency stores, and it is not for brands with no delivery-zone variation. If every pincode you ship to behaves identically, rotation has nothing to rotate and the whole architecture is overhead.
Which plans can run which Functions?
Two different rules get confused with each other constantly.
Public apps containing Functions install on any Shopify plan. Custom apps that use Function APIs directly are limited to Plus and Enterprise stores.
A handful of operations are narrower still, including payment terms and B2B order review, which stay on Plus.
For most Indian D2C brands the practical reading is short. You cannot write your own Function without Plus, and you can install someone else’s on any plan.
That is the change worth noticing. Scripts were a Plus-only capability for their entire existence, so 30 June 2026 was a migration deadline for Plus stores and an opening for everyone else, since custom checkout discount logic is now reachable by installing an app. Which categories deserve that install slot is covered in the stack audit.
What a Script looks like rebuilt as a Function
| Old Script | Function API | What has to change |
|---|---|---|
| Tiered discount by cart value | Discount | Thresholds move from Ruby constants into a metafield the app writes |
| Discount by customer tag | Discount | The tag has to be requested explicitly in the input query |
| Hide a shipping method | Delivery Customization | Custom app on Plus, or a public app that ships one |
| Block COD above a cart value | Payment Customization | Same, and the rule config moves to a metafield |
| Anything reading live external data | Discount plus a scheduled write | The lookup moves out of checkout into a job that writes state ahead of time |
The first four are mechanical. The fifth is where migrations run long, because it is not a port, it is a redesign.
Budget for the input query as its own task. A Script could reach into the cart object freely; a Function only receives the fields you asked for, and forgetting one shows up as a discount that silently does not apply.
Several things a Script used to do are now native settings that need no code at all. Automatic discounts and the order-level changes covered in nine checkout tweaks that lift AOV are worth clearing off the migration list before anyone writes Rust.
Where Functions are still worse than Scripts
Change speed is the honest loss. A Script was edited and saved in a minute; a Function is built, deployed, and released, and if it belongs to a vendor you are waiting on their cycle.
The instruction ceiling is real. Complex logic over large carts hits the 11 million instruction limit, and cart transform work on carts with many line items is where developers meet it first.
Functions cannot see each other. They run in an order Shopify sets, in isolation, so two apps discounting the same cart cannot coordinate and you find out what happens by testing.
Determinism removes conveniences you may not expect. The same input has to return the same output, so anything resembling a clock or a random draw belongs outside the Function, in the state you write beforehand.
Observability is thinner than a console. You get run logs and error statuses in the dashboard, which is enough to find a failing Function and not always enough to explain a merchant’s screenshot.
What to check before installing a Function-based app
Five questions, in the order that saves the most time.
Does it actually ship a Function? Since 30 June 2026 there is no other supported way to discount at Shopify’s checkout. An app that generates codes, rewrites carts, or routes buyers through draft orders is working around the gap, and you can see all three in the buying flow.
What does it gate on? Shopify-owned data such as the delivery address, the customer record, or line items is not shopper-writable. A cart attribute is.
What happens when configuration is missing? A Function with no config should fail closed and apply nothing. Failing open means a bug becomes a sitewide discount at the worst possible hour.
Where does the money live? Any app issuing balances needs a ledger you can audit after a refund, not a counter it can decrement twice.
SB&R is a Shopify app for chained referral rewards. Every referral link belongs to someone who has already bought. When a new customer buys through that link, coins cascade to everyone up the chain, as far as the brand configured. Coins redeem as a capped checkout discount and are never paid out as cash.
SB&R answers that fourth question with an append-only coin ledger that refuses DELETE, three independent anti-bypass checks across the database, the API, and the Shopify Function, and a Function that fails closed when configuration is missing.
How many Functions does it deploy, and what else is already running? Two apps discounting the same cart is a testable question before install and an incident after it. The storefront blocks and Function surfaces most stores never audit are listed in the extensions nobody can ignore, and the payback maths for each category sits in the stack that pays for itself.
If your store never ran a Script, none of this is urgent. The deadline was real for Plus stores with live Ruby in the Script Editor, and for everyone else 30 June 2026 changed nothing that was working. It opened a capability, and an opened capability is worth a fortnight of evaluation, not a migration project.
Questions people actually ask
What replaced Shopify Scripts?
Shopify Functions replaced Shopify Scripts. Functions are WebAssembly modules written in Rust or JavaScript, deployed inside a Shopify app rather than edited in the admin, and executed by Shopify during checkout. Native discount codes and automatic discounts still exist and did not change. Functions are the supported path for custom discount, delivery, and payment logic.
Do Shopify Functions work on plans other than Plus?
Public apps containing Functions install on any Shopify plan, which is the significant change, since Scripts were only ever available on Plus. Custom apps that use Function APIs directly remain limited to Plus and Enterprise stores. A non-Plus merchant gets Function-based discount logic by installing an app, not by writing one.
Can a Shopify Function call an external API?
Not at runtime, in the general case. A fetch target exists for network access, but it is limited to custom apps on Plus and Enterprise stores, requires approval from Shopify, and is unavailable on development stores. Any app that installs across plans has to assume no network access and read its configuration from metafields instead.
What happens to a store that never migrated its Scripts?
Any Script still live on 30 June 2026 stopped executing, with no fallback and no grace period. Checkout keeps working, but the logic disappears: tiered discounts stop applying, hidden shipping methods reappear, and blocked payment methods become available again. Stores that never ran Scripts, which is every store below Plus, lost nothing.
Why do Function-based discounts need a metafield?
A Function cannot fetch its own configuration during checkout, so the rules have to arrive with the input Shopify passes in. Metafields are the durable place to put them. The app writes the current state to a metafield ahead of time, and the Function reads that value while it runs.
How do I tell whether an app discounts through a Function?
Ask what happens at checkout. A Function-based app applies the discount at Shopify's own checkout with no code entry and no redirect. Apps working around the gap typically generate a discount code, rewrite the cart, or route the buyer through a draft order, all of which are visible in the buying flow.
What languages can a Shopify Function be written in?
Anything that compiles to WebAssembly, with Rust and JavaScript being the two paths Shopify documents and tools most heavily. The choice matters less than the input query, because a Function's behaviour is largely determined by which cart and checkout fields it asks Shopify for.
Are Functions faster than an app that rewrites the cart from the storefront?
Materially, yes. A Function runs server-side inside Shopify in under 5 milliseconds and adds nothing to page load. A storefront script that rewrites the cart from the browser adds request time to the shopper's session and can be delayed or blocked by conditions on their device.