---
title: "Shopify Functions: Complete Developer Guide"
description: "In-depth technical guide to Shopify Functions. Wasm architecture, available APIs, CLI workflow, testing, and headless integration."
date: "2026-03-12"
author: "Bastien Allain"
category: "E-commerce"
tags: ["shopify", "functions", "api", "development"]
keywords: ["shopify", "functions", "api", "development"]
image: "/blog/category-ecommerce.webp"
published: true
locale: "en"
translationKey: "shopify-functions-guide"
imageAlt: "Shopify Functions: Complete Developer Guide"
lastmod: "2026-03-12"
authorImage: "/authors/bastien-allain.webp"
authorTwitter: ""
isFamilyFriendly: true
---

Shopify Functions represent a major leap forward in how developers can customize the business logic of a Shopify store. Unlike themes or [Shopify App Extensions](https://shopify.dev/docs/apps/build/app-extensions) that modify the visible interface, Functions operate directly on the backend: they let you inject custom code into Shopify's critical processes, such as discount calculations, cart validation, or delivery and payment option customization at checkout.

## What Are Shopify Functions? The Future of Backend Customization

**Definition:** a Shopify Function is a secure piece of backend code, compiled to **WebAssembly (Wasm)**, executed on Shopify's infrastructure. **Mechanism:** it receives input defined by a **GraphQL** query, applies business logic, and returns a JSON output -- all in under **5 ms**, with no external server required.

Each Function's configuration relies on **metafields**, which allow merchants to adjust the function's behavior without touching code. The entire execution takes place in a sandbox environment compliant with **WASI (WebAssembly System Interface)**, meaning no outbound network calls and no file system access -- a total security guarantee.

For developers and e-commerce agencies, Shopify Functions provide a powerful differentiation lever: they enable custom shopping experiences -- such as complex discounts like "Buy 2 products from Collection A, get 1 product from Collection B at 50% off, restricted to VIP-tagged customers" -- natively integrated into the platform.

### Key Benefits of Shopify Functions

- **Performance**: execution in under 5 ms, compared to 300-800 ms of typical latency for a third-party server. Every 100 ms of reduced latency at checkout can significantly improve conversion rates.
- **Security**: isolated WASI sandbox with no network or file system access.
- **Native scalability**: Shopify's infrastructure handles traffic spikes (Black Friday, flash sales) without any intervention.
- **Reduced operational costs**: no server to host, monitor, or maintain.
- **Unified experience**: customization works across online checkout, Draft Orders, and Shopify POS.
- **Distribution via the [Shopify App Store](https://apps.shopify.com/)**: stores on any plan can benefit from Functions through public apps (custom apps remain restricted to Shopify Plus).

### Beyond the API: A New Customization Philosophy

Historically, customizing Shopify store behavior required webhooks and external servers. The application would receive a notification, process the request on its own server, then send a response back to Shopify. This traditional model, while flexible, introduced significant latency and operational complexity tied to infrastructure management (hosting, monitoring, scalability).

Shopify Functions radically change this paradigm. Instead of a network round-trip, your code runs **directly within Shopify's execution environment**. Shopify orchestrates the call through **extension targets** -- predetermined hook points in the purchase journey, such as `purchase.discount.run` or `purchase.payment-customization.run` -- and executes your logic in a sandbox. The result: customization that integrates seamlessly into the native flow.

This philosophy is part of the broader **Checkout Extensibility** movement, where Shopify progressively opens its architecture to developers through standardized APIs (GraphQL), UI components (Shopify App Extensions), and now backend functions. The goal is clear: enable deep customization while preserving platform stability, security, and performance.

The future looks equally promising. As announced during recent **Shopify Editions**, Shopify continues to expand extension targets -- particularly for post-purchase scenarios and advanced customer object management. Progressive integration with the platform's AI capabilities (Shopify Magic) hints at Functions that can dynamically adapt to each shopper's behavior.

### Shopify Functions vs Shopify Scripts: Strategic Migration Guide

If you have been working in the Shopify ecosystem for several years, you have likely used **Shopify Scripts**, the legacy customization system restricted to Shopify Plus stores. Scripts allowed modifying prices, shipping options, and payment methods through Ruby code executed in the Liquid engine. Shopify Functions are their direct successor, and Scripts is being deprecated.

| Criterion | Shopify Scripts | Shopify Functions |
|---|---|---|
| **Languages** | Ruby (proprietary environment) | **Rust** (recommended), **JavaScript/TypeScript** via [Javy](https://github.com/bytecodealliance/javy), any Wasm-compilable language |
| **Scope** | 3 types (line items, shipping, payment) | **10+ APIs**: discounts, delivery, payment, cart validation, order routing, bundles, fulfillment, pickup |
| **Execution** | Online checkout only | Checkout + **Draft Orders** + **Shopify POS** |
| **Concurrency** | 1 active Script per type | Up to **25 simultaneous functions**, independent |
| **Accessibility** | Shopify Plus only | Public apps (all stores); custom apps (Plus) |
| **Limits** | Undocumented | 10 MB memory, ~256 KB Wasm binary, no outbound network calls |
| **Deployment** | Built-in admin editor | **Shopify CLI** + versioning + app deployment |
| **Configuration** | Ruby code to modify | **Metafields** + App Bridge UI (zero code for merchants) |
| **Advanced use cases** | Simple discounts, basic hiding | Dynamic bundles, complex validation, fulfillment routing, B2B pricing |

For teams still relying on Scripts, here is a structured migration approach:

1. **Audit existing Ruby Scripts**: inventory each active Script, document its business logic, and identify the corresponding Function API (Discount API, Payment Customization API, etc.).
2. **Choose your language**: opt for **Rust** if performance is critical (large carts, complex logic) or **JavaScript/TypeScript** (compiled via **Javy**) if development speed is the priority.
3. **Development and testing**: use the **Shopify CLI** to scaffold the project, write the logic, then test locally with simulated data.
4. **Progressive deployment**: publish the application via the Partner Dashboard and use **metafields** to activate the Function for a subset of customers or markets. Validate results in production before generalizing.
5. **Deactivate Scripts**: once functional parity is confirmed, deactivate the legacy Ruby Scripts.

#### When Functions Are Not the Right Solution

Shopify Functions do not cover every use case:

- **Network calls to an ERP, PIM, or third-party service**: Functions cannot make outbound HTTP calls. Use a webhook coupled with an external server instead.
- **Long-running asynchronous tasks**: complex post-purchase processing exceeding 5 ms goes beyond execution limits. Favor an architecture based on asynchronous jobs.
- **Complex persistent state**: Functions are stateless. If your logic requires maintaining state between executions, combine Functions with metafields or an external database service.

## How Do Shopify Functions Work? Architecture Explained

Understanding the internal architecture of Shopify Functions is essential for using them effectively. Behind the apparent simplicity lies an optimized execution pipeline that combines **GraphQL**, **WebAssembly**, and a system of **extension targets** to guarantee performance and security.

### The Core System: Input, Wasm Logic, and Output

Every Shopify Function follows a three-step execution schema:

1. **Input**: you define a GraphQL query in an `input.graphql` file that specifies exactly which data your function needs -- cart products, customer tags, metafields, amounts. Shopify executes this query and passes the result as a JSON object to your function. This declarative approach ensures only necessary data is transmitted, minimizing memory footprint.

2. **Logic (processing)**: your business code -- compiled into a **WebAssembly** module -- receives this JSON object, applies calculation or validation rules, then generates a result. Code can be written in **Rust** (recommended by Shopify for optimal performance with large carts), **JavaScript/TypeScript** (compiled via Shopify's [Javy](https://github.com/bytecodealliance/javy) tool), or any language supporting Wasm compilation.

3. **Output**: the function returns a JSON object conforming to the output schema defined by the targeted API. For example, a Discount Function returns discount operations to apply; a Payment Customization Function returns operations to hide or reorder payment methods. Shopify applies these instructions instantly in the purchase flow.

### The WebAssembly Advantage: Performance, Security, and Portability

The choice of [WebAssembly (Wasm)](https://webassembly.org/) as the execution format is deliberate. Wasm is a low-level binary format designed for near-native execution in a sandbox environment. Here is why Shopify adopted it:

- **Execution speed**: code is pre-compiled into a compact binary. There is no interpretation or just-in-time (JIT) compilation, ensuring execution times under **5 ms** -- an order of magnitude faster than a typical external API call (300-800 ms).
- **Total isolation**: compliant with the **WASI** specification, each Function runs in a hermetic sandbox. No outbound network access, no file system access, no interaction with other functions.
- **Portability**: the Wasm format is independent of the source language. Whether your team codes in Rust, JavaScript, C++, or any other compilable language, the resulting binary runs identically on Shopify's infrastructure.
- **Optimized size**: Function Wasm binaries are limited to approximately **256 KB**. Partners like [Discount Kit](https://www.shopify.com/partners/blog/discount-kit-shopify-functions-webassembly-api) reduced their function size by **40%** through code optimization, directly translating to faster and more reliable checkouts.

### The Role of Extension Targets in the Shopify Purchase Journey

**Extension targets** are the hook points where Shopify allows execution of your custom code. Each target corresponds to a specific moment in the purchase journey and a specific API.

| Extension Target | Code | Primary Use Case |
|---|---|---|
| **Discount** | `purchase.discount.run` | Complex promotions (tiers, multiple conditions, grouped purchases) |
| **Delivery Customization** | `purchase.delivery-customization.run` | Hide, rename, or reorder delivery options |
| **Payment Customization** | `purchase.payment-customization.run` | Hide or reorder payment gateways |
| **Cart Validation** | `purchase.validation.run` | Validate cart contents (limits, restrictions) |
| **Cart Transform** | `purchase.cart-transform.run` | Merge items into bundles, modify prices |
| **Fulfillment Constraints** | `purchase.fulfillment-constraint.run` | Logistics routing rules (warehouse allocation) |
| **Order Routing** (preview) | `purchase.order-routing-location-rule.run` | Custom ranking of fulfillment locations |

Each target defines available inputs (which data you can request via GraphQL) and the expected output format. Mastering this mapping is the first step in designing effective Functions.

## Your End-to-End Development Workflow

Going from idea to deployment of a Shopify Function follows a structured process, powered by the **[Shopify CLI](https://shopify.dev/docs/apps/tools/cli)** and the Partner Dashboard.

### Prerequisites: Shopify CLI, Partner Account, and Dev Store

Before coding your first Function, make sure you have these elements in place:

- **Node.js** (version 18+) and **npm** or **pnpm** installed on your machine.
- The **Shopify CLI** installed globally (`npm install -g @shopify/cli`).
- An active **[Shopify Partner account](https://www.shopify.com/partners)** with access to the Partner Dashboard.
- A **dev store** associated with your Partner account, with **Checkout Extensibility** enabled.

### Creating Your First Function: File Structure Demystified

Function creation starts with a CLI command that generates a complete project:

```bash
shopify app generate extension --template discount_function --language rust
```

This command creates a directory with the following structure:

- `input.graphql`: the GraphQL query defining input data.
- `src/main.rs` (Rust) or `src/index.js` (JavaScript): the main file containing your business logic.
- `shopify.extension.toml`: the configuration file declaring the extension target, API version, and Function metadata.

Here is a minimal example of an `input.graphql` file for a discount function:

```graphql
query Input {
  cart {
    lines {
      quantity
      merchandise {
        ... on ProductVariant {
          id
          product {
            hasTags(tags: ["VIP-DISCOUNT"]) {
              hasTag: value
            }
          }
        }
      }
    }
  }
  discountNode {
    metafield(namespace: "discount-config", key: "percentage") {
      value
    }
  }
}
```

The `input.graphql` file acts as a contract between your code and Shopify. By requesting only strictly necessary data, you reduce memory footprint and speed up execution.

### Essential Integration with Shopify App Extensions

A Shopify Function never operates alone. It is part of a larger **Shopify application** that can also include **[Shopify App Extensions](https://shopify.dev/docs/apps/build/app-extensions)** for the user interface:

- The **Function** handles backend logic (discount calculation, validation, customization).
- The **App Extension** (via [App Bridge](https://shopify.dev/docs/api/app-bridge) and the Shopify admin) provides the configuration interface that allows merchants to create and manage Function instances without writing a single line of code.

For example, for a custom discount Function, the App Extension displays a form in the Shopify admin where the merchant can define promotion conditions (percentage, targeted collection, required customer tag). These parameters are stored in **metafields** and passed to the Function at each execution.

### Deployment, Versioning, and Merchant Configuration

Once your Function is tested locally, deployment follows this process:

1. **Build**: the Shopify CLI compiles your code into an optimized WebAssembly module.
2. **Deploy**: the `shopify app deploy` command pushes the Wasm binary and configuration to Shopify.
3. **Publication**: via the Partner Dashboard, you publish a new version of your application.
4. **Activation**: the merchant installs the application, then creates a Function instance in their admin (for example, a new discount type). Configuration is done through the App Bridge interface, with no code required.

Shopify manages Function versioning: each deployment creates a new version, and the merchant can revert to a previous version at any time if issues arise.

## Complete Catalog of Shopify Function APIs

Shopify currently offers over **10 Function APIs** covering the entire purchase journey. Here is a structured overview of the main APIs and their practical applications.

### Promotions and Discounts API

The **[Discount Function API](https://shopify.dev/docs/api/functions/reference/product-discounts)** (unified since April 2025, replacing the three former separate APIs: Order Discount, Product Discount, and Shipping Discount) lets you create fully custom discount types.

**Practical use cases:**
- Tiered volume discounts: 10% from 100 USD, 15% from 200 USD, 20% from 300 USD -- no promo code needed.
- Market-conditional promotions: "2 for 22 CAD" in Canada, "2 for 20 USD" in the US, with no exchange rate dependency.
- VIP member discounts: an extra 5% automatically applied to customers tagged "VIP".
- Shipping discounts: 25% off express shipping during the holiday season.

### Delivery Customization API

The **[Delivery Customization API](https://shopify.dev/docs/api/functions/reference/delivery-customization)** lets you sort, rename, hide, or reorder delivery options displayed at checkout.

**Practical use cases:**
- Hide international shipping options for carts containing oversized or fragile items.
- Rename delivery options to add contextual information ("Express delivery -- receive before Christmas").
- Reorder options based on customer preferences or geographic location.

### Payment Customization API

The **[Payment Customization API](https://shopify.dev/docs/api/functions/reference/payment-customization)** controls the display and order of payment gateways at checkout.

**Practical use cases:**
- Hide "Cash on Delivery" for new customers with no purchase history.
- Place the lowest transaction-fee payment gateway at the top position.
- Display specific payment options based on country or cart amount.

### Cart Validation and Transformation APIs

Two complementary APIs handle cart validation and transformation:

- The **[Cart and Checkout Validation API](https://shopify.dev/docs/api/functions/reference/cart-checkout-validation)** blocks order completion when certain conditions are not met (quantity limits per product, age restrictions, login requirements). It also covers express payment options (Apple Pay, Google Pay).
- The **[Cart Transform API](https://shopify.dev/docs/api/functions/reference/cart-transform)** merges items into dynamic bundles, modifies displayed prices, titles, or even cart line images. It is the key tool for creating sophisticated bundled offers.

### Logistics and Order Routing APIs

Several APIs handle post-cart logistics:

- **Fulfillment Constraints Function API** (GA): defines order allocation rules by warehouse (geofencing, split shipping limitation).
- **Local Pickup Delivery Option Generator API** (GA, Shopify Plus): generates custom in-store pickup options with conditional pricing.
- **Pickup Point Delivery Option Generator API** (early access, Plus): generates pickup point delivery options at third-party locations (post offices, partner stores).
- **Order Routing Location Rule API** (developer preview): ranks fulfillment locations using custom logic (proximity, available stock, liquidation priority).
- **Discounts Allocator API** (developer preview): controls discount allocation logic (discount caps, stacking on a single line, application to cheapest item).

## Testing and Debugging Your Shopify Functions

Testing is a critical step often overlooked. A failing Function can block your customers' checkout -- reliability is non-negotiable.

### Unit and Integration Tests Locally

The Shopify CLI lets you test Functions locally before any deployment:

- **Unit tests**: write tests that feed your Function with simulated JSON input objects and verify the output matches expectations. In Rust, use the native test framework (`#[test]`). In JavaScript, use Jest or Vitest.
- **`shopify app function run` command**: executes the Function locally with a manually provided JSON input file, simulating production behavior.
- **Integration tests**: test the Function in the full application context using `shopify app dev` with your dev store. Verify that the configuration interface (App Extension) and backend logic (Function) work in concert.

Here is a Rust unit test example for a discount function:

```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_discount_applied_for_vip() {
        let input = serde_json::from_str::<Input>(
            include_str!("./fixtures/vip_cart.json")
        ).unwrap();

        let result = function(input);

        assert!(result.discount_application_strategy.is_some());
        assert_eq!(result.discounts.len(), 1);
    }

    #[test]
    fn test_no_discount_for_regular_customer() {
        let input = serde_json::from_str::<Input>(
            include_str!("./fixtures/regular_cart.json")
        ).unwrap();

        let result = function(input);

        assert!(result.discounts.is_empty());
    }
}
```

### Logging and Monitoring Strategies in Production

Once deployed, monitoring goes through the **Partner Dashboard**:

- The dedicated Functions page displays **execution metrics**: invocation count, average execution time, errors, and timeouts.
- **Execution logs** help identify edge cases (carts with large numbers of items, unexpected metafield configurations).
- On error, Shopify returns a message in the Function logs. Adopt a structured logging strategy in your code (output to stderr) to facilitate diagnosis.

**Best practice**: set up alerts on error rate and average execution time. Gradual degradation may indicate a performance issue related to catalog growth or cart complexity.

## Understanding and Respecting Technical Limits

Shopify Functions operate in a constrained environment to guarantee overall platform performance. Knowing these limits is essential to avoid production failures.

### Execution, Memory, and Package Size Limits

| Constraint | Limit Value |
|---|---|
| **Execution time** | Target < 5 ms (hard limit is higher, but beyond 5 ms Shopify may throttle) |
| **Memory** | **10 MB** maximum per execution |
| **Wasm binary size** | Approximately **256 KB** maximum |
| **Wasm instructions** | Limit on total instructions executed per invocation |
| **Network calls** | **None** -- no outbound HTTP, fetch, or websocket |
| **File access** | **None** -- strict WASI sandbox |
| **Functions per store** | **25 functions** maximum active simultaneously |
| **State** | **Stateless** -- no persistence between executions |

### Best Practices to Optimize Your Wasm Code

- **Minimize GraphQL input**: request only strictly necessary fields. Each additional field increases JSON input size and parsing time.
- **Choose Rust for large carts**: JavaScript compiled via Javy produces heavier and slower binaries. For stores with 50+ item carts or complex logic, Rust is Shopify's recommended choice.
- **Avoid unnecessary memory allocations**: in Rust, use references rather than copies. In JavaScript, avoid creating large intermediate objects.
- **Test with realistic carts**: simulate the most demanding cases (maximum cart, all conditions active) to verify your Function stays within limits.
- **Optimize binary size**: in Rust, enable compilation optimizations (`opt-level = 'z'`, `lto = true`, `strip = true`). Discount Kit's experience shows that a 40% binary size reduction is achievable with these techniques.

## Advanced Use Cases and Modern Architectures

### Combining Functions and Metafields for Ultra-Personalized Experiences

**Metafields** are the preferred configuration mechanism for Shopify Functions. By defining metafields on products, customers, or the store, you can create Functions whose behavior adapts dynamically:

- **B2B pricing**: a customer metafield indicates their pricing tier. The discount Function automatically applies the correct reduction percentage based on segment.
- **Geographic restrictions**: a product metafield indicates authorized delivery zones. The validation Function blocks the order if the shipping address does not match.
- **Seasonal promotions**: a store metafield defines promotion start and end dates. The Function checks dates at each execution, with no code redeployment needed.

### Integrating Shopify Functions into a Headless Architecture

Shopify Functions are fully compatible with [headless architectures](/blog/e-commerce/shopify-headless-complete-guide) using **Next.js**, **Shopify Hydrogen**, or any other front-end framework connected to the **[Storefront API](/blog/e-commerce/shopify-storefront-api-graphql-guide)**. In a headless architecture:

- The **front-end** (Next.js, Hydrogen) handles display and user experience.
- The **Storefront API** (GraphQL) manages cart and checkout interactions.
- **Shopify Functions** execute automatically on the backend during checkout calculation -- whether the front-end is a classic Liquid theme or a headless application.

The major advantage: your custom business rules (discounts, validation, customization) work identically regardless of the sales channel. A Function deployed once applies to online checkout, POS, Draft Orders, and any headless application connected via the Storefront API.

For agencies deploying [headless architectures on Shopify](/services/builds/shopify-headless), Functions eliminate the need to reimplement business logic on the front-end. Customization remains centralized on the platform, simplifying maintenance and guaranteeing consistency across channels.

## FAQ: Common Questions About Shopify Functions

### What Is the Difference Between Shopify Functions and Legacy Shopify Scripts?

Shopify Scripts is a legacy customization system based on Ruby, restricted to Shopify Plus, and being deprecated. **Shopify Functions** are their successor: they support Rust and JavaScript, cover 10+ APIs (vs. 3 for Scripts), work across all channels (checkout, POS, Draft Orders), and allow 25 simultaneously active functions. Migration is strategically essential before Scripts reach end of support.

### How Do You Test and Debug a Shopify Function Before Deployment?

Use the `shopify app function run` command from the **Shopify CLI** to execute your Function locally with a simulated JSON input file. Write unit tests (native test framework in Rust, Jest or Vitest in JavaScript) and integration tests via `shopify app dev` with a dev store. In production, monitor metrics through the **Partner Dashboard**.

### What Are the Performance Limits of a Shopify Function?

The main limits are: **10 MB of memory** per execution, approximately **256 KB** for the compiled Wasm binary, a target execution time under **5 ms**, and **no outbound network calls**. A store can run up to **25 functions simultaneously**. Functions are stateless: no state is preserved between executions.

### Can You Use Shopify Functions with a Headless Store?

Yes. Shopify Functions execute on the backend, independently of the front-end. Whether you use **Next.js**, **[Shopify Hydrogen](/blog/e-commerce/shopify-headless-complete-guide)**, or any other headless framework connected to the **Storefront API**, Functions apply automatically during checkout calculation. Your custom business rules work identically across all sales channels.
