Most Shopify stores get this wrong — and it costs them revenue.
Shopify Functions Explained: What They Do for Your Store
A technical explainer on Shopify Functions — the Wasm runtime, supported languages (Rust, JS, TS), the seven Function types, and how the architecture compares to a traditional API call.
Updated May 19, 2026
We typically work with Shopify and Shopify Plus stores doing $500k+ in annual revenue.
Published

Shopify Functions are the developer extensibility layer that controls what happens at the most consequential moments of a Shopify store — what discount applies at checkout, which shipping options appear, whether a payment method is shown or hidden, and whether a customer can complete their purchase at all. They run inside Shopify's own infrastructure as WebAssembly (Wasm) modules, written in Rust, JavaScript, or TypeScript, with no cold start and no external HTTP calls. Execution typically completes in under 5 milliseconds.
This piece is a technical explainer. It covers what a Function is at the architecture level, the seven Function types Shopify exposes today, what the code looks like, and where Functions fit relative to apps and the Admin API. If you are a Plus merchant who needs the migration timeline and a step-by-step checklist for moving off Scripts, read the Shopify Scripts deprecation checklist instead — that piece covers the April 15 editing lockout and the June 30 cutoff.
What a Shopify Function actually is
Think of a Function as a small set of rules that Shopify runs automatically at a specific moment during the shopping or checkout process. You define the logic — "if the customer is tagged VIP, apply 15% off" — and Shopify executes it in the background, instantly, every time the condition is met.
Functions are built by developers using JavaScript, TypeScript, or Rust, and they run inside Shopify's own infrastructure. They are not a third-party add-on sitting on a separate server somewhere. They execute in under 5 milliseconds, which for context is faster than a single frame of a 30fps video. That speed matters because this logic runs during checkout, where any delay is felt directly by the customer.
Each Function is pure and self-contained. It receives information about the cart or order, runs its logic, and returns a result. It cannot make calls to external services mid-execution, and it does not store anything between runs. If it needs data from outside Shopify — a tier from your ERP, a customer classification from your CRM — that data needs to be pre-loaded into Shopify's metafields beforehand, where the Function can read it. This is the main constraint that requires planning on complex builds.
Functions are deployed as apps. They live in your codebase, go through your normal development and review process, and can be versioned and rolled back like any other software. This is a significant improvement over the Script Editor, where business-critical logic lived in a web-based text field with no version history.
What your store can actually do with Functions
Shopify currently supports seven types of Functions, each controlling a different part of the commerce experience. Here is what each one means in practice for a store owner.
Discount Functions
Custom pricing rules that the standard Shopify discount system cannot express. Buy-one-get-one logic, tiered pricing that changes based on cart quantity, volume discounts, hidden VIP pricing for tagged customer segments, bundle deals — all of this can be built as a Discount Function. Worth noting: Shopify's native automatic discounts have improved considerably and now handle many simple BOGO and percentage-off scenarios without any custom code. If your pricing logic is straightforward, check the native discount UI before commissioning a Function build.
Cart Transform Functions
Change what appears in the cart itself. Group individual products into a bundle with a shared price, expand a single SKU into its component parts for fulfillment, or modify how line items are displayed. This is what powers native bundle experiences without requiring a third-party app that injects its own cart logic.
Delivery Customization Functions
Control which shipping options customers see at checkout and in what order. Hide specific carriers for certain postal codes, rename a "Standard" rate to something that matches your brand language, surface a same-day option only when the cart contains eligible products, or reorder methods so your preferred carrier appears first. The logic is yours to define.
Payment Customization Functions
Same idea, applied to payment methods. Hide cash-on-delivery for orders above a certain value, suppress certain payment processors for specific geographies, or reorder payment options so your preferred method appears at the top. Up to 25 payment customization Functions can be active on a single store simultaneously.
Cart and Checkout Validation Functions
Block the checkout from proceeding unless specific conditions are met. A sneaker brand running a limited drop can restrict each customer to one pair. A store selling age-restricted products can block checkout from PO boxes. A B2B merchant can enforce minimum order quantities before a buyer can proceed to payment. The validation message surfaces in the checkout UI, and a UI Extension can be added to make the error message match your design.
Order Routing Functions
Determine which of your locations fulfills which items when an order contains products from multiple inventory locations. Rather than relying on Shopify's default routing logic, a Function can apply your own rules — prioritize the warehouse closest to the customer, route fragile items from a specific location, or honor specific fulfillment agreements.
Fulfillment Constraints Functions
Control whether items in an order must ship together or can ship separately. If certain products cannot be split across shipments — hazardous materials, items requiring a signature, products tied to a specific 3PL — a Function can enforce that rule at the order level.
Not sure which Function type fits your use case? We scope custom Function builds in 48 hours. Get a quote and we'll tell you whether your logic needs a custom Function, an existing app, or a different approach entirely.
What the code looks like
Reading code examples is the fastest way to see how straightforward most Function logic actually is. Each of the following is a real, deployable pattern.
Discount Function: VIP pricing for tagged customers
This Function checks whether the customer has a vip tag and applies a 15 percent discount to their entire order if they do. It runs automatically every time a tagged customer reaches checkout.
import type { RunInput, FunctionRunResult } from "../generated/api";
import { DiscountApplicationStrategy } from "../generated/api";
export function run(input: RunInput): FunctionRunResult {
const isVip = input.cart.buyerIdentity?.customer?.hasAnyTag === true;
if (!isVip) {
return {
discounts: [],
discountApplicationStrategy: DiscountApplicationStrategy.First,
};
}
return {
discounts: [
{
message: "VIP 15% off",
targets: [{ orderSubtotal: { excludedVariantIds: [] } }],
value: { percentage: { value: 15.0 } },
},
],
discountApplicationStrategy: DiscountApplicationStrategy.First,
};
}
The Function reads the customer's tags from the cart input, makes a decision, and returns either an empty discount list or the 15% rule. Nothing else happens. No external calls, no database writes.
Delivery Customization Function: hide express shipping for large orders
Hides the Express Shipping option for orders over $500. Large orders often have different handling requirements, and surfacing express options for them can create fulfillment problems.
import type { RunInput, FunctionRunResult } from "../generated/api";
import { HideOperation } from "../generated/api";
const CART_THRESHOLD = 500.0;
const EXPRESS_HANDLE = "express-shipping";
export function run(input: RunInput): FunctionRunResult {
const cartTotal = parseFloat(input.cart.cost.totalAmount.amount);
const operations: HideOperation[] = [];
if (cartTotal > CART_THRESHOLD) {
for (const group of input.deliveryGroups) {
for (const option of group.deliveryOptions) {
if (option.handle === EXPRESS_HANDLE) {
operations.push({ hide: { deliveryOptionHandle: option.handle } });
}
}
}
}
return { operations };
}
This one reads the cart total, checks it against the threshold, and hides the matching delivery option if the condition is met. The merchant controls the threshold and the shipping handle — both can be stored in metafields to make them configurable from the admin without touching code.
Payment Customization Function: hide cash on delivery above a threshold
Removes cash-on-delivery as a payment option for orders above $300. A common scenario for merchants who accept COD for smaller orders but cannot absorb the risk on larger ones.
import type { RunInput, FunctionRunResult } from "../generated/api";
import { HideOperation } from "../generated/api";
const ORDER_LIMIT = 300.0;
const COD_NAME = "Cash on Delivery";
export function run(input: RunInput): FunctionRunResult {
const cartTotal = parseFloat(input.cart.cost.totalAmount.amount);
const operations: HideOperation[] = [];
if (cartTotal > ORDER_LIMIT) {
for (const method of input.paymentMethods) {
if (method.name === COD_NAME) {
operations.push({ hide: { paymentMethodId: method.id } });
}
}
}
return { operations };
}
Same pattern as the delivery example. Read the cart total, compare against a threshold, hide the matching payment method. The complexity in a real engagement is usually in the data plumbing — making the threshold and method name configurable per market rather than hardcoded — not in the Function itself.
Custom build vs. app: how to decide
Not every use case requires a custom Function. Shopify's App Store now has a mature category of discount, checkout, and shipping apps built on Functions, maintained by third-party vendors, and configurable through a no-code admin interface. For standard use cases — volume discounts, basic shipping rules, common BOGO patterns — an app is faster to deploy, cheaper to maintain, and does not create an internal engineering dependency.
Custom Functions make sense when the logic is genuinely proprietary, involves data from your own systems (an ERP, a loyalty platform, a pricing engine), or cannot be expressed through an app's configuration interface. If you need a discount rule that reads a customer's tier from your external CRM and applies different rates per product category, no app will expose that level of specificity. That is when a custom build is the right call.
The decision framework is straightforward: check the App Store first. If an existing app handles the use case with a configuration interface you can manage without engineering support, use it. If the logic requires data or conditions the app cannot reach, build a custom Function.
When the logic is genuinely proprietary, that's the work we do. Our Shopify development services cover Function builds for established DTC brands whose pricing, shipping, or checkout logic has outgrown what off-the-shelf apps can express.
What it takes to deploy one
Functions are deployed through the Shopify CLI, packaged as part of a Shopify app (public or custom), and activated from the Shopify admin or via a GraphQL mutation. The workflow for a new Function looks like this:
# Scaffold a new Function extension inside your app
shopify app generate extension
# Test the Function locally with real input data
shopify app function run
# Deploy to production
shopify app deploy
Local testing uses input data that mirrors what Shopify would send in production, so you can verify the logic against realistic cart compositions, customer tags, and order values before anything touches the live store. This is a significant improvement over the Script Editor, where testing meant running logic against live traffic and hoping.
Once deployed, Functions appear in the relevant section of your Shopify admin — Discount Functions in the Discounts section, Payment Customization Functions in Settings > Payments, and so on. Activating and deactivating them requires no code change.
A few practical limits worth knowing
The 5 ms execution budget is the most important constraint for complex logic. In practice this is generous for standard use cases — most well-written Functions complete in one to two milliseconds — but if you are trying to process a cart with thousands of line items against a complex pricing matrix, the ceiling becomes relevant. Pre-computing where possible and keeping logic lean is the design principle.
The 256 KB compiled binary size limit rarely causes problems for typical Function logic but is worth knowing if you are considering embedding large lookup tables directly in the code. Store that data in metafields instead.
Functions cannot make network requests during execution. They are pure: input in, output out. Any data from outside Shopify needs to arrive before the Function runs, stored in metafields that the Function reads from its GraphQL input. This is the constraint that most often requires architectural design work on a new engagement.
Further reading
Related Shugert resources
- Shopify Scripts deprecation — what every Plus merchant must do
- Shopify Development Guide: themes, apps, Functions & headless
- Custom Shopify solutions for established brands
At Shugert, we build Shopify Functions for established DTC brands that need pricing, shipping, or checkout logic their existing app stack cannot handle. That work sits inside our Shopify development services, either as a fixed-scope project or as part of an ongoing retainer. Get a quote and we'll come back with a scope within 48 hours.
Keep reading
Related resources

Shopify Plus Migration: When to Upgrade in 2026
When to upgrade to Shopify Plus, how the Shopify-to-Plus migration actually works, real 2026 costs, and the upgrade checklist. Field notes from 30+ Plus migrations.

Shopify Scripts Deprecation: Plus Migration Checklist
Shopify Scripts stop running on June 30, 2026, and the editing lockout starts April 15. This is the step-by-step migration checklist Plus merchants need to ship Functions before the deadline.