User to Cart

Shopify Functions: custom discounts, delivery, payment and cart logic

Shopify Functions let you replace parts of Shopify's backend logic with your own code: discounts Shopify doesn't offer natively, bundles, rules for which delivery and payment options appear, and validation that stops an invalid order at checkout. Functions are compiled to WebAssembly, ship inside an app, and run on Shopify's infrastructure at the right moment in the cart and checkout. They are also the replacement for Shopify Scripts, which stopped running on June 30, 2026.

The Function APIs

Function APIWhat it doesTypical uses
DiscountAdds product, order and shipping discountsTiered pricing, BOGO, bundles, customer-specific discounts, free shipping rules
Cart TransformExpands, merges or updates cart linesBundles and kits, add-ons shown as one line
Delivery CustomizationHides, renames, reorders delivery optionsHide express for PO boxes, rename rates, sort local delivery first
Payment CustomizationHides, renames, reorders payment methodsInvoice only for B2B, hide COD above a value
Cart and Checkout ValidationBlocks progress with errorsQuantity limits, restricted items, required data, PO number rules
Fulfillment ConstraintsControls how items are fulfilled togetherShip certain items from one location
Order Routing Location RuleRanks locations for fulfillmentCustom location priority
Pickup point / Local pickup generatorsGenerate pickup optionsCustom pickup networks

Shopify allows up to 25 active functions per Function API for payment customizations, delivery customizations, validations and fulfillment constraints, so unrelated rules can live in separate, simpler functions.

Plan requirements

  • Public apps from the App Store that contain Functions: usable on any plan.
  • Custom apps that contain Functions: usable only on Shopify Plus.
  • Some capabilities are Plus-only inside an API. For example, a payment customization on a non-Plus store hides the whole payment method rather than an individual placement.
  • Network access from Functions is available primarily to Shopify for enterprises merchants, for specific Function APIs.

This is why the same requirement may be a custom app for a Plus store and a public app for a store on another plan.

How a Function is built

A Function is an extension inside an app, generated with Shopify CLI:

shopify app generate extension --template discount

It has three parts: configuration, an input query that declares the data it needs, and the run code that returns operations. Here is a tiered order discount that reads its tiers from a metafield, so merchants can change thresholds without a deploy.

Configuration

# extensions/tiered-discount/shopify.extension.toml
api_version = "2026-07"

[[extensions]]
name = "Tiered order discount"
handle = "tiered-discount"
type = "function"

[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/cart_lines_discounts_generate_run.graphql"
export = "cart-lines-discounts-generate-run"

[extensions.build]
command = ""
path = "dist/function.wasm"

Input query

# src/cart_lines_discounts_generate_run.graphql
query CartInput {
  cart {
    cost {
      subtotalAmount {
        amount
      }
    }
  }
  discount {
    discountClasses
    metafield(namespace: "$app", key: "function-configuration") {
      jsonValue
    }
  }
}

Run function

// src/cart_lines_discounts_generate_run.js
import {DiscountClass, OrderDiscountSelectionStrategy} from '../generated/api';

// Config example: {"tiers":[{"minSubtotal":100,"percentage":5},{"minSubtotal":250,"percentage":10}]}
export function cartLinesDiscountsGenerateRun(input) {
  if (!input.discount.discountClasses.includes(DiscountClass.Order)) {
    return {operations: []};
  }

  const tiers = input.discount.metafield?.jsonValue?.tiers ?? [];
  const subtotal = Number(input.cart.cost.subtotalAmount.amount);
  const tier = tiers
    .filter((t) => subtotal >= t.minSubtotal)
    .sort((a, b) => b.percentage - a.percentage)[0];

  if (!tier) return {operations: []};

  return {
    operations: [
      {
        orderDiscountsAdd: {
          candidates: [
            {
              message: `${tier.percentage}% off`,
              targets: [{orderSubtotal: {excludedCartLineIds: []}}],
              value: {percentage: {value: tier.percentage}},
            },
          ],
          selectionStrategy: OrderDiscountSelectionStrategy.First,
        },
      },
    ],
  };
}

The function never fetches data and never touches the cart directly. Shopify gives it exactly what the input query asks for, and applies the operations it returns. That's what makes Functions fast and safe to run at checkout scale.

Validation, delivery and payment: the same shape

The other APIs follow the same pattern with different targets and operations:

  • Validation (cart.validations.generate.run) returns validationAdd operations with error messages and targets such as $.cart. Its input includes the buyer journey step, so you can validate only at checkout.
  • Delivery customization (cart.delivery-options.transform.run) returns operations such as deliveryOptionHide for a delivery option handle.
  • Payment customization (cart.payment-methods.transform.run) returns operations such as paymentMethodHide for a payment method ID.
  • Cart transform (cart.transform.run) returns expand and merge operations, reading bundle definitions from metafields.

Configuration: metafields, not code

Well-built Functions keep their rules in metafields on the discount, customization or shop: thresholds, tiers, excluded products, customer tags. An admin UI in your app, or an admin UI extension, lets the merchant edit them. The function code stays the same while the business changes its rules.

Limits to design around

  • Functions have no network access by default. Put the data they need into metafields ahead of time.
  • Execution has resource limits, so keep input queries small and logic simple. Request only the fields you use.
  • Functions are deterministic: same input, same output. No clocks, randomness or state between runs. Use metafields updated by your app for time-based rules.
  • Some behaviours are fixed by Shopify. For example, wallets can't be renamed by a payment customization, and payment customizations don't run in POS.

Testing and rollout

  • Unit-test the run function with JSON input fixtures, which is easy because it's a pure function.
  • Use shopify app function run and the function logs in the dashboard to replay real inputs.
  • Deploy, then activate the discount or customization for a test segment first, such as a customer tag or a single market, before turning it on for everyone.

Decision checklist

  • Which Function API matches the requirement? Could a native setting do it?
  • Is the store on Plus (custom app possible) or not (public app needed)?
  • What data does the function need, and which metafields will hold it?
  • Who will change the rules, and through what UI?
  • How will you test it with real carts before launch?

Frequently asked questions

What are Shopify Functions?

Shopify Functions are small programs, compiled to WebAssembly, that Shopify runs on its own infrastructure to customize backend logic: discounts, cart line transformations, delivery and payment options, validation and fulfillment. They ship inside an app, receive a GraphQL-shaped input and return a list of operations Shopify applies.

Do Shopify Functions require Shopify Plus?

It depends on how they're distributed. Stores on any plan can use public App Store apps that contain Functions. Custom apps that contain Functions can only be used by stores on Shopify Plus. Some individual capabilities, such as hiding specific payment method placements, are Plus-only as well.

What is a Shopify discount function?

A discount Function implements a discount type Shopify doesn't offer natively. The current Discount Function API can return product, order and shipping discounts from one function, using targets such as cart.lines.discounts.generate.run for cart lines and cart.delivery-options.discounts.generate.run for delivery. Merchants create discounts from your function in the admin like any other discount.

What is the Shopify cart transform function used for?

Cart Transform changes how lines appear in the cart and checkout, most often for bundles: expanding one bundle product into its component items, or merging several lines into one bundle line. It's how many bundle apps work.

What is Shopify delivery customization and payment customization?

They are two Function APIs that change the options a buyer sees at checkout. Delivery customization can hide, rename or reorder shipping and delivery options. Payment customization can hide, rename or reorder payment methods, with some limits, for example wallets such as Apple Pay can't be renamed.

Can a Shopify Function call an external API?

Normally no; Functions get their data from the input query, including metafields. Network access for Functions exists for some Function APIs but is available primarily to merchants on Shopify for enterprises and must be enabled by Shopify. The usual pattern is to write the data your function needs into metafields ahead of time.

  • Scripts to Functions migration

    Shopify Scripts stopped running on June 30, 2026. How to migrate line item, shipping and payment scripts from Script Editor to Shopify Functions, with a pattern-by-pattern mapping, example code and a migration plan.

  • Checkout UI extensions

    How Shopify Checkout UI extensions work: targets, the Preact and Polaris web components API, settings, cart metafields, blocking progress, network access and plan limits, with a complete extension example.

  • Shopify B2B

    What Shopify B2B includes on each plan since April 2026, how companies, catalogs, volume pricing, payment terms and purchase orders work, and which B2B requirements need a custom Shopify B2B app or ERP integration.

  • Hire a Shopify app developer

    Freelance Shopify app developer for custom app development, ERP and accounting integrations, Checkout UI extensions and Shopify Functions. How an engagement works and what to prepare.