Enterprise commerce runs on edge cases — complex discount stacks, custom checkout flows, market-specific pricing, bespoke B2B rules. Until recently, Shopify merchants had to bolt on external services or wrestle with brittle script hacks to make this work. Shopify Functions changes that entirely.
What are Shopify Functions?
Shopify Functions are server-side WebAssembly (Wasm) modules that run directly inside Shopify's infrastructure — not on your servers. They let you extend and override core commerce logic: discounts, shipping, payment methods, cart validation, order routing, and more.
The key insight: instead of calling out to an external webhook and waiting for a response, your custom logic executes inside Shopify's request pipeline, in milliseconds, with zero cold starts and no infrastructure to manage.
"Functions give enterprise teams the ability to write custom commerce logic that's as fast and reliable as Shopify's own platform — without maintaining separate microservices."
How they work
You write a Function in any language that compiles to WebAssembly — most commonly Rust or JavaScript via the Javy runtime. Shopify calls your Function with a JSON input payload at a defined hook point, and your code returns a JSON output that Shopify executes.
// Rust — discount function skeleton
use shopify_function::prelude::*;
// Shopify calls this with cart + customer context
fn function(input: Input) -> FunctionResult<Output> {
let discounts = input.cart.lines
.iter()
.filter_map(|line| {
// Apply 20% to orders over $500
if line.cost.total_amount.amount > 500.0 {
Some(build_percentage_discount(line, 20.0))
} else { None }
})
.collect();
Ok(Output { discounts, discount_application_strategy: Strategy::Maximum })
}
Function types available to merchants
As of 2026, Shopify exposes the following Function APIs. Each targets a specific hook in the checkout and order lifecycle:
- Discount — Create percentage, fixed-amount, or free-shipping discounts with full conditional logic: volume tiers, customer tags, metafield gates, product bundles.
- Shipping — Filter, rename, reorder, or hide shipping methods per cart contents, customer location, or B2B account attributes.
- Payment — Control which payment methods appear at checkout. Block COD for certain regions, show net-terms for approved B2B buyers, hide BNPL for restricted SKUs.
- Cart Transform — Merge, expand, or modify cart lines server-side. Power bundle mechanics, configurable products, and add-on logic without front-end hacks.
- Order Routing (Shopify Plus) — Assign orders to specific fulfillment locations based on custom rules: split shipments, warehouse priority, carrier preferences.
- Validation — Block checkout completion based on cart state. Enforce minimum order values, restrict product combinations, validate B2B purchase orders.
Why this matters for enterprise
Traditional Shopify customisation for at-scale merchants meant one of three things: Shopify Scripts (deprecated, Ruby-only, no external data access), webhook-driven external services (latency, reliability, infra cost), or custom storefronts that sacrifice platform features.
Functions collapse this tradeoff. Here's a direct comparison:
| Capability | Shopify Scripts | External Webhook | Shopify Functions |
|---|---|---|---|
| Execution latency | ~50ms | 100–500ms+ | <5ms |
| External API calls | ✗ | ✓ | ✗ (by design) |
| Metafield access | ✗ | ✓ | ✓ (via input query) |
| Infrastructure to host | None | Required | None |
| Shopify-managed SLA | ✓ | ✗ | ✓ |
| Version control & CI/CD | Limited | ✓ | ✓ (via Shopify CLI) |
| Future availability | Deprecated | ✓ | ✓ |
⚠️ Note: No external calls inside Functions. Functions are intentionally sandboxed — they cannot make HTTP requests to external APIs at runtime. Data you need must be fetched at query time (via the input query) or stored in metafields/metaobjects before the Function runs.
Enterprise use cases in the wild
- B2B tiered pricing — Apply account-specific discount tiers from metafields without a third-party pricing app.
- Bundle mechanics — Merge component lines into a single bundle line with Cart Transform, keeping inventory logic clean.
- Market-specific shipping — Hide express options in certain countries or require freight quotes above a weight threshold.
- Checkout validation — Block orders that fail minimum quantity rules or that mix restricted product categories.
- Payment method gating — Surface net-30 terms only to verified B2B accounts tagged in your customer metafields.
- Order routing — Route orders to the nearest warehouse or split shipments across facilities by inventory availability.
Getting started: your first Function
-
Install Shopify CLI 3+ and initialise a new app with
shopify app init. Functions are packaged as app extensions inside a Shopify app. -
Generate a Function extension:
shopify app generate extension --type discount. Choose Rust or JavaScript as your target language. -
Define your input query in
input.graphql. This GraphQL query tells Shopify what cart, customer, and metafield data to pass into your Function at runtime. -
Write your logic, compile to Wasm with
cargo build --target wasm32-wasi, and test locally using the Shopify Function Runner. -
Deploy with
shopify app deploy. Activate the Function from your Shopify admin under Discounts, Shipping, or the relevant surface.
# GraphQL — input query example
query RunInput {
cart {
cost { totalAmount { amount } }
buyerIdentity {
customer {
metafield(namespace: "b2b", key: "tier") {
value # e.g. "gold" | "silver" | "standard"
}
}
}
lines(first: 250) {
nodes {
quantity
merchandise { ... on ProductVariant { id price { amount } } }
}
}
}
}
Limits to know before you build
Functions are powerful, but they have hard boundaries designed to ensure platform reliability:
| Limit | Value |
|---|---|
| Max execution time | 5ms (hard cap) |
| Max Wasm binary size | 256 KB (compressed) |
| Max input/output payload | 64 KB each |
| No network I/O at runtime | Sandboxed — fetch not available |
| Max cart lines in input query | 250 |
| Functions per store | Unlimited (per app extension) |
The 5ms execution budget forces a useful discipline: your Function must be a pure, stateless transform of the data Shopify hands it — no lazy data fetching, no side effects.
Functions vs. apps: when to use what
Functions aren't a replacement for app logic — they're the final mile. Use a Shopify app to manage configuration, sync data into metafields, handle webhooks, and serve your admin UI. Use Functions to apply that pre-loaded configuration at checkout speed.
A common enterprise pattern: a background worker syncs your ERP's pricing rules into product metafields nightly. At checkout, a Discount Function reads those metafields from its input query and applies the correct tiered price — no external call, no latency, no failure mode.
Ready to extend your checkout?
Start with Shopify's official Function documentation and the shopify-function Rust crate — both are comprehensive and actively maintained.
If you're evaluating whether Functions can power a specific business requirement — B2B pricing, bundle mechanics, custom checkout validation — the best starting point is mapping your edge case to one of the six Function API types above, then sketching your input query. The logic usually turns out to be simpler than you expect once the data is in scope.