Checkout Functions vs UI extensions: which one owns the discount

A merchant sets up a discount, tests it in checkout, watches it apply, and then watches it vanish at the payment step. Or the discount applies to the wrong products. Or it applies twice. The bug report blames the UI extension, because the UI is where the discount is visible. The bug is almost never in the UI. The discount logic lives in a Shopify Function, which runs server side and the buyer never sees. The UI extension only displays what the Function decided. Debugging the display when the decision is wrong is debugging the wrong layer.

Checkout extensibility splits the work into layers, and the split is the whole point. UI extensions add approved components at set points in checkout: a banner, a field, a delivery notice. Functions run the business logic the buyer never sees: discounts, delivery and payment customization, cart validation. A discount is logic, so it belongs in a Function. A field that collects a gift message is UI, so it belongs in an extension. Mixing the two up is how discounts vanish and fields break.

What each layer can and cannot do

A Function can hide a payment method for orders over a threshold, apply a discount to a collection, or block checkout when a cart fails validation. It cannot render anything, because it never touches the page. A UI extension can add a custom field, show a message, or offer an upsell at an approved extension point. It cannot change a price, hide a payment method, or decide eligibility, because it runs in the browser and the buyer could tamper with it.

That boundary is a security decision, not a limitation to work around. Prices and eligibility are decided server side because the server is the only place the merchant controls. Anything decided in the browser can be changed in the browser. A discount computed in a UI extension is a discount the shopper can edit, which is why Shopify does not allow it.

The plan boundary that surprises people

UI extensions on the information, shipping, and payment steps are Plus only. A Basic store cannot add UI to those steps, whatever app it installs. Public apps containing Functions work on any plan, but a custom app containing Functions is Plus only, which means a Basic store can install a discount app from the App Store but cannot commission its own. That is the line Shopify drew, and it is the line that decides whether a customization is a configuration task or a plan upgrade.

Checkout.liquid is gone, and Shopify Scripts were deprecated on June 30, 2026, with published scripts deactivated. The stores still running on scripts are running on borrowed time, and the migration is to Functions for logic and UI extensions for display. The stores that migrate cleanly are the ones that sort their customizations by layer first, and move each one to the layer that owns it.

How to decide which layer a change belongs in

Ask one question: does this change what the shopper sees, or what the shopper pays? If it changes what they see, it is a UI extension. If it changes what they pay, or whether they can pay a certain way, it is a Function. If it changes both, it is two changes, and they need to be built and tested separately, because the failure modes are different and the debugging is different. The discount that vanishes at payment is a Function bug. The field that never appears is an extension bug. Knowing which is which is half the fix.

Keep reading: Shopify Plus checkout customization: what is actually possible in the editor and what needs functions, Postcode lookup at checkout: the address autocomplete errors nobody logs.

Frequently asked questions

What is the difference between a Shopify Function and a UI extension?

A Function runs server side business logic the buyer never sees, like discounts and payment rules. A UI extension adds visible components at approved points in checkout, like fields and banners. Logic belongs in Functions, display belongs in extensions.

Why did my discount disappear at the payment step?

Almost always a Function problem, not a UI problem. The UI extension only displays what the Function decided. If the Function's eligibility or discount logic is wrong, the discount vanishes when the Function runs, whatever the display showed.

Can a Basic Shopify store use checkout UI extensions?

Only on the thank you and order status pages. UI extensions on the information, shipping, and payment steps are Plus only. Public apps with Functions work on any plan, but custom apps with Functions are Plus only.

Is checkout.liquid still usable?

No. Checkout.liquid is retired, and Shopify Scripts were deprecated on June 30, 2026. Checkout Extensibility, Functions for logic and UI extensions for display, is the only supported path.